Subchapter 24.26
deploy/references/preflight-checks.mdMarkdown4 KBView on GitHub
Pre-deployment validation steps. Run after user approval, before deployment execution.
AppOnboard runs direct deployment (no
azd).
Branch on scaffold-manifest.json.iacFormat:
Also bundled
PHASEdeployaz account showENVIRONMENT_BLOCKING. Suggest az login (plain, no scope).az login --scope https://graph.microsoft.com/.default — Graph scope is irrelevant for ARM deployments.Check globally-unique names before deploy: az acr check-name, az storage account check-name, az webapp show, az keyvault show. Name taken → suggest alternate from prepare-plan.json.naming.suffix: “Name {name} taken. Use {altName}?”
If plan includes F1/D1/free SKUs, surface at deploy gate (do NOT block):
⚠️ Free tier: no custom domains, no SSL, no always-on, 60 min/day compute (F1). Dev/test only.
az role assignment list --assignee {userId} --scope /subscriptions/{sub} --query "[].roleDefinitionName" -o tsvSubscription-scope deploy requires Contributor/Owner on subscription. Missing → ENVIRONMENT_BLOCKING with az role assignment create command.
⛔ MANDATORY — do NOT skip. What-if validates + previews in one call. Use what-if exclusively — az deployment sub/group validate hits a known CLI bug (HTTP stream consumed error). If what-if fails, log + warn user — do not skip to execution.
az deployment sub what-if \
--name "{deploymentName}" \
--location {location} \
--template-file infra/main.bicep \
--parameters @infra/main.parameters.json \
--subscription {subscriptionId} \
--what-if-result-format FullResourcePayloadsaz deployment group create \
--resource-group {rg} \
--template-file infra/main.bicep \
--parameters @infra/main.parameters.json \
--subscription {subscriptionId} \
--what-if \
--what-if-result-format FullResourcePayloadsCreate, Modify, Delete, NoChange. Surface Delete as warnings — user must acknowledge.ENVIRONMENT_BLOCKING.terraform plan -out=tfplan -detailed-exitcodedestroy as warnings — user must acknowledge. Auth error → ENVIRONMENT_BLOCKING.az role assignment list \
--assignee {currentUserObjectId} \
--scope /subscriptions/{sub}/resourceGroups/{rg} \
--query "[].roleDefinitionName" -o tsvRequired: Contributor or Owner on the target resource group. If missing → ENVIRONMENT_BLOCKING with remediation command.
⛔ what-if does NOT catch quota errors. It returns Succeeded even when target SKU has limit=0.
If prepare-plan.json.quotaValidation.verified == true → proceed.
Otherwise → read sku-quota-validation.md and run direct quota checks NOW (per-provider API patterns, offer restrictions). If limit=0 → HALT, present region fallback. Skip regions in quotaValidation.checkedRegions with zero availability.
⛔ SubscriptionIsOverQuotaForSku or LocationIsOfferRestricted in deploy output → HALT. See error-classification.md.
az group show --name {rg} --query "location" -o tsv 2>/dev/nullprepare-plan.json region. Mismatch → warn.main.bicep has subscription scope).Each check runs independently. Collect all results, then present structured report.
| Check | Fail Behavior |
|---|---|
| Deployment preview | Warn, don’t block (can fail on unsupported types) |
| RBAC | Block. Surface az role assignment create. |
| RG check | Warn on location mismatch. Don’t block. |
## Preflight Results
✅ IaC syntax: valid (terraform validate / bicep build)
⚠️ Deployment preview: 3 creates, 0 destroys, 1 update
✅ RBAC: Contributor role confirmed
✅ Resource group: rg-myapp-dev (eastus2)