microsoft/aspire · error · InvalidOperationException

Azure deployment for

Error message

Azure deployment for {resource.Name} failed.

What it means

When reconciling a Bicep deployment, Aspire reads the ARM deployment's ProvisioningState. If ARM reports the deployment Failed, Aspire persists that terminal failure state, publishes an 'Azure deployment failed' state to the dashboard, and throws InvalidOperationException so the failure surfaces immediately instead of being silently retried. This preserves ARM's authoritative failure outcome for the adopted/reconciled deployment.

Solutions

  1. Open the Azure portal (Resource Group > Deployments > failed deployment > Error details) or run az deployment group show to read the ARM error code and message.
  2. Fix the underlying template/parameter/quota/RP-registration error reported by ARM, then re-run the app host.
  3. Register any missing resource providers (az provider register --namespace <ns>) or request a quota increase if the error says so.
  4. Delete the failed deployment and any partially created resources, then re-run to start a clean deployment.
  5. Validate the Bicep locally before deploying (az bicep build / what-if) to catch template errors early.

Example fix

// before
# failed: ProviderRegistration "Microsoft.App" missing
az deployment group show -g my-rg -n <failed-deployment> --query properties.error

// after
az provider register --namespace Microsoft.App
az provider show -n Microsoft.App --query registrationState   # wait for Registered
# re-run the AppHost so the deployment retries cleanly
Defensive patterns

Strategy: try-catch

Validate before calling

var deployment = await armClient.GetArmResource(deploymentId).GetAsync(ct);
if (string.Equals(deployment.Value.Data.ProvisioningState, "Failed", StringComparison.OrdinalIgnoreCase))
{
    var error = deployment.Value.Data.Error; // inspect before re-attempting
}

Try / catch

try
{
    await provisioner.GetOrCreateResourceAsync(resource, context, ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("failed"))
{
    logger.LogError(ex, "Azure deployment failed (ARM terminal state). Inspect deployment error details in the portal.");
}

Prevention

When it happens

Trigger: Calling GetOrCreateResourceAsync / ReconcileDeploymentStateAsync (or TryAdoptActiveDeploymentConflictAsync while adopting an active conflicting deployment) against a deployment whose latest ARM provisioning state is 'Failed' — e.g. the Bicep template was rejected by ARM, a nested resource failed, quota/RP registration errors, or a prior run's deployment already failed.

Common situations: Invalid Bicep parameters or template errors; resource name conflicts or quota exceeded in the region; a resource provider not registered on the subscription; re-running the app host against a resource group whose previous deployment failed.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/5ae02aad9afe22f1. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Azure/Provisioning/Provisioners/BicepProvisioner.cs:433

                cancellationToken).ConfigureAwait(false);
        }

        if (string.Equals(deployment.ProvisioningState, DeploymentStateProvisioningStateCanceled, StringComparisons.AzureProvisioningState))
        {
            // Preserve ARM's terminal cancellation so the dashboard explains why this
            // resource stopped instead of silently retrying.
            await PersistReconciledProvisioningStateAsync(stateSection, DeploymentStateProvisioningStateCanceled, cancellationToken).ConfigureAwait(false);
            await PublishReconciledTerminalStateAsync(resource, AzureProvisioningStrings.ResourceStateAzureDeploymentCanceled).ConfigureAwait(false);
            throw new InvalidOperationException($"Azure deployment for {resource.Name} was canceled.");
        }

        if (string.Equals(deployment.ProvisioningState, DeploymentStateProvisioningStateFailed, StringComparisons.AzureProvisioningState))
        {
            // Preserve ARM's terminal failure for the same reason as cancellation:
            // this is the outcome of the adopted deployment.
            await PersistReconciledProvisioningStateAsync(stateSection, DeploymentStateProvisioningStateFailed, cancellationToken).ConfigureAwait(false);
            await PublishReconciledTerminalStateAsync(resource, AzureProvisioningStrings.ResourceStateAzureDeploymentFailed).ConfigureAwait(false);
            throw new InvalidOperationException($"Azure deployment for {resource.Name} failed.");
        }

        return false;
    }

    private async Task PersistReconciledProvisioningStateAsync(DeploymentStateSection stateSection, string provisioningState, CancellationToken cancellationToken)
    {
        stateSection.Data[DeploymentStateProvisioningStateKey] = provisioningState;
        await deploymentStateManager.SaveSectionAsync(stateSection, cancellationToken).ConfigureAwait(false);
    }

    private async Task PublishReconciledTerminalStateAsync(AzureBicepResource resource, string state)
    {
        await notificationService.PublishUpdateAsync(resource, snapshot => snapshot with
        {
            State = new(state, KnownResourceStateStyles.Error)
        }).ConfigureAwait(false);
    }

View on GitHub (pinned to 25830f84bd)