Home / Azure

AzureCheat sheetBeginner

Azure deployment failed: find the real error behind DeploymentFailed, a cheat sheet

An ARM or Bicep deployment fails with a generic DeploymentFailed message. Pull the failing operation and its real error code, then match it to the fix.

Deepak Bhardwaj7 min read

Applies toAzure Resource Manager deployments (ARM templates and Bicep); Azure CLI 2.x; Az PowerShell

The symptom: a pipeline or az deployment group create stops with DeploymentFailed and "At least one resource deployment operation failed". That code tells you nothing useful. The real error sits on the individual operation that failed, and with Bicep modules it can be one or two levels down.

The commands below use rg-prod and my-deployment. Replace them with your own names.

Find the failed deployment

az deployment group list -g rg-prod \
  --query "sort_by([?properties.provisioningState=='Failed'], &properties.timestamp)[-5:].{name:name, time:properties.timestamp, code:properties.error.code}" \
  -o table

If the deployment isn't listed, it probably failed before it started. Validation and preflight errors don't appear in deployment history. Skip to errors that never reach history.

Get the real error

Start with the top-level error and its details:

az deployment group show -g rg-prod -n my-deployment --query properties.error -o json

Then list only the failed operations, with the resource each one was working on:

az deployment operation group list -g rg-prod -n my-deployment \
  --query "[?properties.provisioningState=='Failed'].{resource:properties.targetResource.resourceName, type:properties.targetResource.resourceType, code:properties.statusMessage.error.code, message:properties.statusMessage.error.message}" \
  -o json

The PowerShell equivalent:

Get-AzResourceGroupDeploymentOperation -ResourceGroupName rg-prod -DeploymentName my-deployment |
  Where-Object ProvisioningState -eq 'Failed' |
  Format-List

Follow nested deployments down

Each Bicep module runs as its own deployment. If the failed operation has the type Microsoft.Resources/deployments, its resource value is the name of a nested deployment. Run the same query against that name:

az deployment operation group list -g rg-prod -n <module-deployment-name> \
  --query "[?properties.provisioningState=='Failed'].{resource:properties.targetResource.resourceName, type:properties.targetResource.resourceType, code:properties.statusMessage.error.code, message:properties.statusMessage.error.message}" \
  -o json

Repeat until the type is a real resource. A module scoped to another resource group has its history there, so change -g to match.

Other scopes

Scope Show the deployment List operations
Resource group az deployment group show -g <rg> -n <name> az deployment operation group list -g <rg> -n <name>
Subscription az deployment sub show -n <name> az deployment operation sub list -n <name>
Management group az deployment mg show -m <mg> -n <name> az deployment operation mg list -m <mg> -n <name>
Tenant az deployment tenant show -n <name> az deployment operation tenant list -n <name>

Error code to fix

Microsoft's list of common codes is longer than this. These are the ones you'll usually hit:

Error code Cause Fix
DeploymentFailed Generic wrapper Read the operations, as above
InvalidTemplate, InvalidTemplateDeployment Syntax, parameter or template validation failure Read the message; run validate
AuthorizationFailed The identity lacks the action at this scope, or a provider isn't registered Check role and scope: RBAC cheat sheet
LinkedAuthorizationFailed No permission on a linked resource, such as joining a subnet, or it's in another tenant Grant the action named in the message on the linked scope
RequestDisallowedByPolicy An Azure Policy denied the resource Find the policy assignment
MissingSubscriptionRegistration, NoRegisteredProviderFound Resource provider isn't registered, or the type or API version isn't available there Register the provider and check supported locations
SkuNotAvailable The size isn't offered in that region or zone Pick another size: VM allocation errors
OperationNotAllowed, ResourceQuotaExceeded Quota exceeded, or the operation isn't allowed on that SKU Check usage; free capacity or request more
Conflict The operation isn't allowed in the resource's current state Wait, or change state first (for example, deallocate before a disk resize)
AnotherOperationInProgress Another operation is running on the same resource Wait and retry; serialize the pipeline
DeploymentActiveAndUneditable A deployment with this name is still running Wait, or cancel it
DeploymentQuotaExceeded The resource group reached 800 deployments in history Delete old history
DeploymentNameLengthLimitExceeded Deployment name is over 64 characters Shorten it, including generated module names
ParentResourceNotFound Child resource deployed before its parent exists Add parent or a dependency
ResourceNotFound, InvalidResourceReference A reference points to something missing or not yet created Fix the name or add a dependency
PropertyChangeNotAllowed A property can't be changed after creation Keep the old value, or recreate the resource
StorageAccountAlreadyTaken Storage account names are globally unique Use another name, for example with uniqueString()
SubnetIsFull No free addresses in the subnet Use another subnet or expand the range
ScopeLocked A resource lock blocks the change Manage locks safely

Quick checks for common fixes

# Provider registration state, then register
az provider show -n Microsoft.ContainerService --query registrationState -o tsv
az provider register -n Microsoft.ContainerService --wait

# VM quota and size availability
az vm list-usage -l eastus -o table
az vm list-skus -l eastus --size Standard_D4s_v5 --all -o table

# What's running right now in this resource group
az deployment group list -g rg-prod \
  --filter "provisioningState eq 'Running'" --query "[].name" -o tsv

Cancel a running deployment only if you're sure it's stuck or wrong:

az deployment group cancel -g rg-prod -n my-deployment

Warning

Cancelling doesn't roll back. Resources that were already created or changed stay as they are. Review the state and run what-if before you deploy again.

Errors that never reach history

Validation and preflight failures are in the Activity Log, not in deployment history. To reproduce one and see the message directly:

az deployment group validate -g rg-prod -f main.bicep -p params.json

To read it from the log:

az monitor activity-log list -g rg-prod --offset 6h --status Failed \
  --query "[].{time:eventTimestamp, op:operationName.value, resource:resourceId, msg:properties.statusMessage}" \
  -o json

To collect everything from a single deployment attempt, use its correlation ID:

corr=$(az deployment group show -g rg-prod -n my-deployment --query properties.correlationId -o tsv)
az monitor activity-log list --correlation-id "$corr" --offset 7d --status Failed -o json

When the message is still too vague

Debug logging records the request and response of each operation. You can only turn it on with Azure PowerShell, not the CLI:

New-AzResourceGroupDeployment -Name debug-run -ResourceGroupName rg-prod `
  -TemplateFile main.bicep -DeploymentDebugLogLevel All

Then read the content with PowerShell or the CLI:

az deployment operation group list -g rg-prod -n debug-run --query "[].properties.response" -o json
az deployment operation group list -g rg-prod -n debug-run --query "[].properties.request" -o json

Caution

Debug output stays in deployment history and can include passwords and other secure values you passed in. Delete the entry when you're done. This removes the history record, not the deployed resources:

az deployment group delete -g rg-prod -n debug-run

Clear deployment history

Resource Manager normally deletes old deployments automatically as you near the 800 limit. That can still fail, for example if there's a CanNotDelete lock on the resource group, if you opted out, or if many deployments run at once.

az lock list -g rg-prod -o table
az deployment group delete -g rg-prod -n <old-deployment-name>

Prevent it next time

  • Gate pipelines on validate and what-if. This catches template, policy and many permission errors before anything changes:
az bicep build --file main.bicep
az deployment group validate -g rg-prod -f main.bicep -p params.json
az deployment group what-if -g rg-prod -f main.bicep -p params.json
  • Print the failed operations in the pipeline. Add the operations query as a step that runs on failure, so the real code is in the job log.
  • Use unique, short deployment names, such as the build ID. This avoids DeploymentActiveAndUneditable from a re-used name and keeps each run traceable.
  • Register providers ahead of time in your subscription setup.
  • Stop drift and leftovers with what-if gates and deployment stacks.