IaC Error Guide: 'InvalidTemplate' Bicep Deployment & BCP Compile Errors
Fix Bicep BCP compile errors and Deployment failed with InvalidTemplate: diagnose BCP033 type mismatch, missing parameters, circular dependencies, and bad ARM expressions.
- #iac
- #troubleshooting
- #errors
- #bicep
Overview
Bicep failures fall into two distinct phases. A BCP-coded error is a compile-time failure: the Bicep CLI refuses to transpile your .bicep file into an ARM JSON template, so nothing is ever sent to Azure. An InvalidTemplate error is a deploy-time failure: the file compiled fine, but Azure Resource Manager rejected the generated ARM template — usually because an expression cannot be resolved, a parameter is missing, or two resources depend on each other in a cycle.
A compile error looks like this:
main.bicep(42,28) : Error BCP033: Expected a value of type "string" but the provided value is of type "int".
A deploy-time rejection looks like this:
ERROR: {"code": "InvalidTemplate", "message": "Deployment template validation failed: 'The template resource 'storageAccount' reference to 'vnet' requires an API version. Please see https://aka.ms/arm-template for usage details.'."}
The key distinction: if you see a BCP code, az bicep build failed and the deployment never started. If you see InvalidTemplate, the build succeeded but ARM validation failed. The fix path differs completely, so always identify which phase failed first.
Symptoms
az deployment group createexits non-zero withBCP-prefixed errors and a line/column reference.az deployment group createreturnsDeployment failed with InvalidTemplateafter a clean compile.az bicep buildwrites nothing and prints type or syntax errors.- A
what-ifpreview fails before showing any change set.
az deployment group create \
--resource-group rg-prod-eastus \
--template-file main.bicep \
--parameters @params.json
ERROR: {"status":"Failed","error":{"code":"InvalidTemplate","message":"Deployment template validation failed: 'The template parameter 'adminPassword' is not found in the template. Please see https://aka.ms/arm-template for usage details.'.","additionalInfo":[{"type":"TemplateViolation"}]}}
Common Root Causes
1. BCP033 — type mismatch
A value’s type does not match what the property or parameter expects. Passing an int where a string is required, or an object where an array is required, triggers BCP033 at compile time.
az bicep build --file main.bicep
main.bicep(42,28) : Error BCP033: Expected a value of type "string" but the provided value is of type "int". [https://aka.ms/bicep/core-diagnostics#BCP033]
Here line 42 passes enableHttpsTrafficOnly: 1 instead of enableHttpsTrafficOnly: true, or name: 7 where a string is required. Fix the literal or wrap it (string(myInt)).
2. BCP028 — duplicate identifier
The same symbol name is declared twice — two param, var, resource, or module statements share an identifier. Bicep cannot disambiguate them.
az bicep build --file main.bicep
main.bicep(58,11) : Error BCP028: Identifier "location" is declared multiple times. Remove or rename the duplicates. [https://aka.ms/bicep/core-diagnostics#BCP028]
This usually happens after copy-pasting a param location string block, or declaring both a param storageName and a var storageName. Rename one.
3. BCP018 — missing required property / character
The compiler expected a token (a colon, brace, or required property) and did not find it. Often a resource is missing a required field, or a syntax element was dropped.
az bicep build --file main.bicep
main.bicep(73,3) : Error BCP018: Expected the ":" character at this location. [https://aka.ms/bicep/core-diagnostics#BCP018]
main.bicep(81,1) : Error BCP035: The specified "resource" declaration is missing the following required properties: "sku". [https://aka.ms/bicep/core-diagnostics#BCP035]
Add the missing colon or required property. az bicep build lists every required property by name in the BCP035 companion error.
4. InvalidTemplate from an unresolved reference or bad ARM expression
The file compiled, but the generated ARM expression references something that does not exist at deploy time — a reference() to a resource that was never declared, or a missing apiVersion. ARM only catches this during validation.
az deployment group validate \
--resource-group rg-prod-eastus \
--template-file main.bicep \
--parameters @params.json
ERROR: {"code":"InvalidTemplate","message":"Deployment template validation failed: 'The template resource 'nsgRule' at line '0' and column '0' is not valid: The language expression property 'subnetId' can't be evaluated.'."}
The expression refers to a symbolic name or output that resolves to null. Confirm the referenced resource is actually declared and spelled correctly.
5. Missing parameter
A parameter has no default and was not supplied in the parameters file or on the command line. ARM rejects the template because a required value is absent.
az deployment group create \
--resource-group rg-prod-eastus \
--template-file main.bicep \
--parameters @params.json
ERROR: {"code":"InvalidTemplate","message":"Deployment template validation failed: 'The value for the template parameter 'adminPassword' at line '1' and column '20' is not provided. Please see https://aka.ms/arm-deploy/#parameter-file for usage details.'."}
Add the value to params.json or pass --parameters adminPassword=<value>. For secrets, reference a Key Vault in the parameters file rather than hard-coding.
6. Circular dependency, unsupported API version, or scope/linked-template mismatch
Two resources reference each other (dependsOn cycle), the apiVersion on a resource type is not recognized in the target region, or a module is deployed at the wrong scope (a subscription-scoped resource referenced from a resource-group deployment).
az bicep build --file main.bicep
az deployment group create --resource-group rg-prod-eastus --template-file main.bicep
main.bicep(90,1) : Error BCP080: The expression is involved in a cycle ("storageAccount" -> "diagnosticSettings" -> "storageAccount"). [https://aka.ms/bicep/core-diagnostics#BCP080]
ERROR: {"code":"InvalidTemplate","message":"Deployment template validation failed: 'The resource type 'Microsoft.Network/privateEndpoints' does not support API version '2018-01-01' in location 'westus3'.'."}
Break the cycle by removing one direction of the reference, bump the apiVersion to one the region supports, or correct the module scope property.
Diagnostic Workflow
Step 1: Determine the failure phase
az bicep build --file main.bicep --stdout > /dev/null
If this prints BCP errors, it is a compile failure — fix those first; the deployment never ran. If it succeeds silently, the failure is at deploy time (InvalidTemplate).
Step 2: Lint and read the BCP codes
az bicep lint --file main.bicep
Each error includes a file, line, column, code, and a docs link. Address the first error first — later errors are often cascade noise from the first.
Step 3: Validate against ARM without deploying
az deployment group validate \
--resource-group rg-prod-eastus \
--template-file main.bicep \
--parameters @params.json
validate runs the same template checks as a real deployment but provisions nothing. It surfaces InvalidTemplate, missing parameters, and unsupported API versions safely.
Step 4: Preview the change set with what-if
az deployment group what-if \
--resource-group rg-prod-eastus \
--template-file main.bicep \
--parameters @params.json
what-if resolves expressions and shows the resources that would be created/modified. If it fails before printing a change set, the template still has an unresolved reference.
Step 5: Inspect failed deployment operations
az deployment operation group list \
--resource-group rg-prod-eastus \
--name main \
--query "[?properties.provisioningState=='Failed'].{res:properties.targetResource.resourceName, msg:properties.statusMessage}" \
-o jsonpath 2>/dev/null || \
az deployment operation group list -g rg-prod-eastus -n main -o table
This pinpoints which resource operation failed and the ARM status message for it — essential when a multi-resource template partially deploys.
Example Root Cause Analysis
A pipeline runs az deployment group create for main.bicep and fails with:
ERROR: {"code":"InvalidTemplate","message":"Deployment template validation failed: 'The template resource 'privateEndpoint' reference to 'storageAccount' requires an API version. Please see https://aka.ms/arm-template for usage details.'."}
First, confirm the phase. az bicep build --file main.bicep --stdout > /dev/null succeeds — so this is deploy-time, not a compile error. Running validate reproduces it cleanly. Reading the template, the private endpoint references the storage account by its raw resource ID string rather than its symbolic name:
privateLinkServiceId: '/subscriptions/.../storageAccounts/${storageName}'
Because the ID is a concatenated string, ARM has no symbolic dependency and cannot infer the API version of the target — it wants an explicit reference() with a version. The fix is to reference the resource by its Bicep symbolic name so the dependency and API version are inferred:
# change the property to use the symbolic resource reference, then:
az deployment group validate -g rg-prod-eastus --template-file main.bicep --parameters @params.json
After switching privateLinkServiceId: storageAccount.id, validate passes and the deployment proceeds. The root cause was a hand-built resource ID defeating Bicep’s automatic dependency inference.
Prevention Best Practices
- Run
az bicep buildandaz bicep lintin CI on every commit soBCPerrors fail fast, before a deployment is ever attempted. - Add
az deployment group validateandaz deployment group what-ifas a required gate in pull requests — they catchInvalidTemplateand unsupported API versions without touching production. - Reference resources by their Bicep symbolic name (
storageAccount.id) instead of hand-built ID strings so dependencies and API versions are inferred automatically. - Keep secrets out of parameter files by referencing Key Vault, and give every required parameter a sensible default or an explicit value in each environment’s
params.json. - Pin and review
apiVersionvalues against the regions you deploy to; an API version valid in one region may be unsupported in another. See more in infrastructure-as-code guides. - When a deployment fails mid-run, the free incident assistant can summarize the ARM operation log into the failing resource and likely cause.
Quick Command Reference
# Compile only — surfaces BCP errors before any deploy
az bicep build --file main.bicep
# Lint for style and correctness
az bicep lint --file main.bicep
# Validate against ARM without provisioning anything
az deployment group validate -g rg-prod-eastus --template-file main.bicep --parameters @params.json
# Preview the resolved change set
az deployment group what-if -g rg-prod-eastus --template-file main.bicep --parameters @params.json
# Deploy
az deployment group create -g rg-prod-eastus --template-file main.bicep --parameters @params.json
# Inspect which operation failed
az deployment operation group list -g rg-prod-eastus -n main -o table
Conclusion
A Bicep failure is either a compile-time BCP error (the build never produced a template) or a deploy-time InvalidTemplate (ARM rejected the generated JSON). Identify the phase first, then work the cause:
- BCP033 — a value’s type does not match the expected property or parameter type.
- BCP028 — an identifier (param/var/resource/module) is declared more than once.
- BCP018/BCP035 — a required character or required resource property is missing.
- InvalidTemplate from an unresolved
reference()or a hand-built ID with no API version. - A required parameter has no default and was not supplied.
- A circular
dependsOn, an unsupportedapiVersionin the region, or a module deployed at the wrong scope.
Run build, lint, validate, and what-if as CI gates and most of these never reach a real deployment.
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.