Find the real error in a failed Bicep or ARM deployment
Get from "DeploymentFailed" to the operation that failed and its own error code — compile and validate first, read the failed operations of the deployment (and of each module's nested deployment), find validation and preflight errors in the Activity log by correlation ID, turn on request and response logging once, and from TypeScript read the same with @azure/arm-resourcesdeployments.
markdownguidev15C5S-R6WXstage: operatetrust: officialservice: armservice: bicepinterface: cliinterface: iacinterface: sdkDeploymentFaileddeployment failed find erroraz deployment operation group listaz deployment group show errornested deployment module errorActivity log correlation id deploymentaz monitor activity-log listvalidation error not in deployment historybicep build errorsaz deployment group validatedebugSetting detailLevel--debug Azure CLIdeployment operations TypeScriptDeploymentsClient
Errors live in three places, depending on when they happened. Compile errors come from bicep build. Validation and preflight errors are in the Activity log and never in deployment history. Errors while resources were being created are in the deployment's operations. Look in that order.
1. Compile and validate locally
bicep build main.bicep # or: az bicep build --file main.bicep
az deployment group validate --resource-group rg-app --template-file main.bicep --parameters main.bicepparam
bicep build prints main.bicep(22,51) : Error BCP… with line and column. Type mismatches (BCP035, BCP036, BCP037) are warnings: the build succeeds and Azure refuses the deployment later, so read them (reference/bicep/compile-errors.md). validate runs preflight: SKU availability, policy, quota, permission checks.
2. Read the failed operations
az deployment group show --resource-group rg-app --name main \
--query "properties.{state:provisioningState, error:error}"
az deployment operation group list --resource-group rg-app --name main \
--query "[?properties.provisioningState=='Failed'].{resource:properties.targetResource.id, type:properties.targetResource.resourceType, error:properties.statusMessage}"
The first gives the wrapper (DeploymentFailed) and its details[]. The second gives each failed resource with its own code. Look the code up in reference/arm/deployment-errors.md or reference/arm/errors.md.
Modules are nested deployments. A failed operation of type Microsoft.Resources/deployments is a module; its name is the module's deployment name. Run the same operation group list with --name <module-deployment-name> (and --resource-group of the module's scope) to see inside it. Repeat until you reach a resource type that isn't deployments.
Other scopes use az deployment operation sub list, … mg list and … tenant list, with az deployment sub show and so on.
3. Nothing in deployment history? Read the Activity log
A deployment that failed validation or preflight leaves no history entry. Find it by the time or by the correlation ID the CLI printed:
az monitor activity-log list --resource-group rg-app --status Failed --offset 1h \
--query "[].{op:operationName.value, status:status.value, msg:properties.statusMessage}" -o json
az monitor activity-log list --correlation-id <id>
4. Still unclear: log the requests once
- CLI: add
--debugto the deployment command. - Template: set
debugSetting.detailLeveltorequestContent, responseContenton the deployment (ARM nested deployments have the same property). The operations then carry each request and response.
Both can expose secrets and parameter values. Turn them on for one run, then off, and don't paste the output anywhere public.
5. From TypeScript
Since @azure/arm-resources 8.0.0 (July 2026), deployments live in their own package, @azure/arm-resourcesdeployments:
import { DefaultAzureCredential } from "@azure/identity";
import { DeploymentsClient } from "@azure/arm-resourcesdeployments";
const client = new DeploymentsClient(new DefaultAzureCredential(), process.env.AZURE_SUBSCRIPTION_ID ?? "");
export async function failedOperations(resourceGroup: string, deployment: string) {
const d = await client.deployments.get(resourceGroup, deployment);
console.log(d.properties?.provisioningState, JSON.stringify(d.properties?.error));
for await (const op of client.deploymentOperations.list(resourceGroup, deployment)) {
if (op.properties?.provisioningState === "Failed") {
console.log(op.properties.targetResource?.id, JSON.stringify(op.properties.statusMessage));
}
}
}
Next
Template and dependency errors: reference/arm/deployment-errors.md. Subscription, quota and SKU errors: reference/arm/errors.md.