Azure Error Guide: 'InvalidTemplateDeployment' ARM/Bicep Failures
Fix Azure InvalidTemplateDeployment and DeploymentFailed: diagnose ARM/Bicep schema errors, policy denials, bad parameters, dependsOn ordering, and API versions.
- #azure
- #troubleshooting
- #errors
- #arm
Overview
An Azure InvalidTemplateDeployment happens when Azure Resource Manager rejects a deployment before or during provisioning — the template parsed, but a pre-flight check, a parameter, a policy, or a resource operation failed. ARM wraps the underlying reason inside the InvalidTemplateDeployment envelope, so the real cause is almost always in a nested error.details block rather than the top-level message. A related DeploymentFailed appears when validation passed but a resource failed to provision at runtime.
You will see this in the CLI output or pipeline log:
(InvalidTemplateDeployment) The template deployment failed with error: 'The resource operation completed with terminal provisioning state 'Failed'.'
Code: InvalidTemplateDeployment
Message: The template deployment failed with error: ...
And the nested detail (the part that actually matters) reads like this:
{
"code": "InvalidTemplateDeployment",
"details": [
{
"code": "RequestDisallowedByPolicy",
"message": "Resource 'stprod001' was disallowed by policy. Policy identifiers: 'Deny storage accounts without HTTPS'. ..."
}
]
}
It occurs at az deployment group create time, in pipelines running ARM/Bicep, or during what-if and validate pre-flight. Because the envelope is generic, the fix depends entirely on the nested details[].code — schema, policy, parameter, dependency, or API version.
Symptoms
az deployment group createfails with(InvalidTemplateDeployment)and a generic top-level message.- A nested
details[].codereveals the real cause (RequestDisallowedByPolicy,InvalidTemplate,MissingRegistrationForLocation, etc.). DeploymentFailedappears withterminal provisioning state 'Failed'for a specific resource.az deployment group validaterejects the template even before any resource is touched.
az deployment group create \
--resource-group rg-prod \
--template-file main.bicep \
--parameters @prod.parameters.json
(InvalidTemplateDeployment) The template deployment failed with error: 'The resource operation completed with terminal provisioning state 'Failed'.'
Inner Errors:
{"code":"RequestDisallowedByPolicy","target":"stprod001"}
az deployment operation group list \
--resource-group rg-prod --name main \
--query "[?properties.provisioningState=='Failed'].properties.statusMessage.error" -o json
[ { "code": "RequestDisallowedByPolicy", "message": "Resource 'stprod001' was disallowed by policy..." } ]
Common Root Causes
1. Schema or validation error in the ARM/Bicep template
A malformed resource, an unknown property, or a Bicep syntax error fails compilation or ARM schema validation before deployment.
az bicep build --file main.bicep --stdout 1>/dev/null
Error BCP037: The property "skuName" is not allowed on objects of type "Microsoft.Storage/storageAccounts". Permissible properties include "sku".
az bicep build surfaces the exact line and property before ARM ever sees it.
2. Policy denial nested in InvalidTemplateDeployment
Azure Policy with a deny effect blocks the resource, and ARM reports it as RequestDisallowedByPolicy inside the InvalidTemplateDeployment envelope.
az deployment operation group list \
--resource-group rg-prod --name main \
--query "[?contains(properties.statusMessage.error.code, 'Policy')].properties.statusMessage.error" -o json
[ { "code": "RequestDisallowedByPolicy",
"message": "Resource 'stprod001' was disallowed by policy. Policy identifiers: '[{\"policyAssignment\":{\"name\":\"Deny storage without HTTPS\"}}]'." } ]
The policy assignment name in the message tells you exactly which rule to satisfy.
3. Missing or invalid parameter
A required parameter has no value, or a supplied value violates an allowedValues / @allowed constraint.
az deployment group validate \
--resource-group rg-prod \
--template-file main.bicep \
--parameters @prod.parameters.json
(InvalidTemplate) Deployment template validation failed: 'The provided value 'Standard_ZZZ' for the template parameter 'skuName' is not valid. The parameter value is not part of the allowed values: 'Standard_LRS', 'Standard_GRS'.'
4. Resource dependency ordering (dependsOn)
A resource references another that has not been created yet because an implicit reference or explicit dependsOn is missing, so ARM tries them out of order.
az deployment operation group list \
--resource-group rg-prod --name main \
--query "[?properties.provisioningState=='Failed'].{res:properties.targetResource.resourceType, msg:properties.statusMessage.error.message}" -o json
[ { "res": "Microsoft.Network/networkInterfaces",
"msg": "Resource '/subscriptions/.../subnets/app' referenced by resource '/subscriptions/.../networkInterfaces/nic-01' was not found. ... It is possible that the referenced resource was not deployed yet." } ]
The “was not deployed yet” hint means the NIC needs a dependsOn (or a reference()) to the subnet.
5. API version mismatch
The apiVersion on a resource does not support a property used in the template, or is not available in the target region.
az provider show --namespace Microsoft.Storage \
--query "resourceTypes[?resourceType=='storageAccounts'].apiVersions[] | [0:5]" -o tsv
2023-05-01
2023-04-01
2023-01-01
2022-09-01
2022-05-01
If the template pins an apiVersion not in this list, switch to a supported one shown here.
6. Pre-flight validation passes but runtime fails (DeploymentFailed)
validate and what-if only check what ARM can know ahead of time; a quota shortfall, a name collision, or a backend failure surfaces only at provision time as DeploymentFailed.
az deployment operation group list \
--resource-group rg-prod --name main \
--query "[?properties.statusMessage.error.code=='QuotaExceeded'].properties.statusMessage.error" -o json
[ { "code": "QuotaExceeded",
"message": "Operation could not be completed as it results in exceeding approved standardDSv3Family Cores quota. Current Limit: 10, ..." } ]
A clean validate followed by a runtime QuotaExceeded confirms it is a provisioning-time failure, not a template flaw.
Diagnostic Workflow
Step 1: Compile the template locally first
az bicep build --file main.bicep --stdout 1>/dev/null
# (for ARM JSON, this step is skipped)
Step 2: Run pre-flight validation
az deployment group validate \
--resource-group rg-prod \
--template-file main.bicep \
--parameters @prod.parameters.json
Step 3: Preview the resource graph with what-if
az deployment group what-if \
--resource-group rg-prod \
--template-file main.bicep \
--parameters @prod.parameters.json
Step 4: Extract the nested error from the failed deployment
az deployment operation group list \
--resource-group rg-prod --name main \
--query "[?properties.provisioningState=='Failed'].properties.statusMessage.error" -o json
The nested code (policy, quota, parameter, dependency) is what you actually fix.
Step 5: Confirm a supported API version when the error points at properties
az provider show --namespace <Namespace> \
--query "resourceTypes[?resourceType=='<type>'].apiVersions" -o tsv
Example Root Cause Analysis
A Bicep deployment that creates a VNet, subnet, NIC, and VM fails with the generic envelope:
(InvalidTemplateDeployment) The template deployment failed with error: 'The resource operation completed with terminal provisioning state 'Failed'.'
The top-level message says nothing useful, so the nested operation error is pulled:
az deployment operation group list \
--resource-group rg-net --name main \
--query "[?properties.provisioningState=='Failed'].{res:properties.targetResource.resourceType, msg:properties.statusMessage.error.message}" -o json
[ { "res": "Microsoft.Network/networkInterfaces",
"msg": "Resource '/subscriptions/.../virtualNetworks/vnet-app/subnets/app' referenced by resource 'nic-01' was not found. It is possible that the referenced resource was not deployed yet." } ]
The NIC references the subnet by a constructed resourceId() string rather than by symbolic reference, so Bicep never inferred an implicit dependency and ARM tried to create the NIC before the subnet existed. A what-if would have shown the NIC and subnet as parallel, not ordered.
Fix: reference the subnet symbolically (or add an explicit dependsOn) so ARM orders the creation correctly, then re-validate before re-deploying:
# after switching nic to: subnet: { id: appSubnet.id }
az bicep build --file main.bicep --stdout 1>/dev/null
az deployment group validate -g rg-net --template-file main.bicep --parameters @prod.parameters.json
az deployment group create -g rg-net --template-file main.bicep --parameters @prod.parameters.json
The symbolic reference creates an implicit dependsOn, the subnet provisions first, and the NIC and VM reach Succeeded.
Prevention Best Practices
- Compile Bicep with
az bicep buildand runaz deployment group validatein CI on every pull request so schema, parameter, and API-version errors fail fast before any resource is touched. - Run
az deployment group what-ifagainst the target environment to preview the resource graph and catch unexpected changes or ordering issues. - Prefer symbolic references over hand-built
resourceId()strings so Bicep infersdependsOnfor you and dependency-ordering failures disappear. - Test against the same Azure Policy assignments that production enforces; policy denials only appear when the deployment hits a scope with the
denyeffect. - Pin
apiVersionvalues to ones returned byaz provider showand review them when adopting new resource properties. See more in the Azure guides. - For ad-hoc triage, the free incident assistant can unwrap an
InvalidTemplateDeploymentenvelope and surface the nesteddetails[].codethat you actually need to fix.
Quick Command Reference
# Compile Bicep locally (surfaces schema errors)
az bicep build --file main.bicep --stdout 1>/dev/null
# Pre-flight validation
az deployment group validate -g <RG> --template-file main.bicep --parameters @params.json
# Preview the resource graph
az deployment group what-if -g <RG> --template-file main.bicep --parameters @params.json
# Pull the nested error from a failed deployment (the real cause)
az deployment operation group list -g <RG> --name <DEPLOYMENT> \
--query "[?properties.provisioningState=='Failed'].properties.statusMessage.error" -o json
# Isolate policy denials
az deployment operation group list -g <RG> --name <DEPLOYMENT> \
--query "[?contains(properties.statusMessage.error.code,'Policy')].properties.statusMessage.error" -o json
# List supported API versions for a resource type
az provider show --namespace Microsoft.Storage \
--query "resourceTypes[?resourceType=='storageAccounts'].apiVersions" -o tsv
# Re-deploy after fixing
az deployment group create -g <RG> --template-file main.bicep --parameters @params.json
Conclusion
An InvalidTemplateDeployment is a generic envelope around a specific nested failure; a DeploymentFailed means validation passed but a resource failed at provision time. The usual root causes:
- A schema or syntax error in the ARM/Bicep template that fails compilation or validation.
- An Azure Policy
denyeffect reported asRequestDisallowedByPolicyinside the envelope. - A missing required parameter or a value outside the allowed set.
- A resource dependency-ordering problem from a missing
dependsOnor symbolic reference. - An
apiVersionthat does not support a used property or is unavailable in the region. - A runtime-only failure (quota, name collision) that pre-flight validation cannot catch.
Always pull the nested details[].code from the failed deployment operation first — the envelope is generic, but the inner error tells you exactly what to fix.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.