An r/AZURE thread this week (40 comments) was looking for a small database in West Europe and could not find a single available size; the replies mixed capacity, retiring sizes and quota. Azure returns three different errors that look the same from the portal: AllocationFailed, SkuNotAvailable and the quota one, OperationNotAllowed. Each has a different cause and a different fix, and only one of them can be solved by retrying. It is Azure's counterpart to OCI's "Out of host capacity", which has its own note with a retry loop. Everything below comes from learn.microsoft.com; the sources are at the end.
The three errors
-
AllocationFailedorZonalAllocationFailed: "Allocation failed. We do not have sufficient capacity for the requested VM size in this region". This is capacity: right now there are no free hosts for that size in the region or zone. It shows up on create, on starting a deallocated VM or on resizing one. It is the only one a retry can solve. -
SkuNotAvailable: "The requested size for resource … is currently not available in location … zones … for subscription …". The size is not offered to your subscription in that region or zone. With an ARM template or Bicep file it arrives asInvalidTemplateDeploymentduring validation: the deployment never starts and the error is only in the activity log. Retrying changes nothing. - Quota:
OperationNotAllowedwith "Operation results in exceeding quota limits of Core. Maximum allowed: 4, Current in use: 4, Additional requested: 2". It is a limit on your subscription, not missing hardware: you fix it by requesting more quota or freeing vCPUs.
Microsoft says it on its quotas page: Azure checks quota and capacity separately. Plenty of quota does not guarantee capacity, and capacity does not help if the quota is full.
SkuNotAvailable: read the restriction instead of guessing
The portal only shows the sizes that pass; it never says why the rest are missing. az vm list-skus with --all includes the ones not available to your subscription and prints the restriction:
# B-family sizes in the region, restricted ones included az vm list-skus --location westeurope --size Standard_B --all --output table # the restriction object for one size az vm list-skus --location westeurope --size Standard_B2s --all \ --query "[?name=='Standard_B2s'].restrictions" # VMs only, with per-zone detail az vm list-skus --location westeurope --resource-type virtualMachines --zone --all --output table The Restrictions column (in JSON, the restrictions field the Resource Skus API returns) carries the two values that decide what to do:
-
type:Locationif the size is restricted across the whole region,Zoneif only in some zones. In that caserestrictionInfo.zoneslists the closed zones, and the others can still take the size. -
reasonCode: in the case the documentation shows,NotAvailableForSubscription: the region does not offer that size to your subscription.
If the size is restricted across the region and you need it there, Microsoft says to ask Support with a SKU request. If it is only restricted in one zone, the way out is another zone or dropping the zone constraint. Spot VMs also return SkuNotAvailable when there is no Spot capacity in the region. For Azure Database for PostgreSQL Flexible Server, the equivalent is az postgres flexible-server list-skus --location <region>.
Quota: two tiers per region, and stopped VMs count too
vCPU quota has two tiers per subscription and per region: Total Regional vCPUs and a per-family quota (for example, Standard DSv3 Family vCPUs), plus a cap on the number of VMs. A new VM has to fit in both vCPU quotas. One detail that trips people up: quota is calculated from cores in use, allocated and deallocated, so a stopped (deallocated) VM keeps holding quota even though it is not billed for compute.
# usage and limit of every compute quota in the region az vm list-usage --location westeurope --output table The fix is an increase request (Subscription → Usage + quotas) or deleting the VMs nobody uses; deallocating them is not enough.
AllocationFailed: what to change for each case
- Standalone VM (no availability set or proximity placement group): retry later, another size, or another region or zone. Microsoft presents it as a temporary workaround until capacity is back.
- Availability set: adding a VM, resizing, or starting only some of the deallocated VMs is requested from the set's original cluster, which may have no room. Stopping (deallocating) every VM in the set and starting them together lets the allocation search all clusters.
- Zones: creating the VM from a snapshot of the OS disk in another zone, or without a zone constraint, opens the allocation to the whole region.
-
OverconstrainedAllocationRequestorOverconstrainedZonalAllocationRequest: the combination of requirements does not fit. Microsoft names accelerated networking, zone, ephemeral disk, proximity placement group and Ultra or Premium SSD v2 disks; dropping one can be enough even when the size has capacity. - Older sizes (Av1, Dv1, DSv1, D15v2, DS15v2): they do not run on the newest hardware and fail more often. The recommendation is to move to Av2, Dv3/DSv3 or Ev3/ESv3.
If the capacity must be there no matter what, there is On-demand Capacity Reservation: it holds the room in advance, but it is billed at the VM's rate even when the reservation is unused.
A retry that does not burn hours on what will not change
Before leaving a loop retrying, rule out the two errors that do not change over time: list-usage to see whether it is quota and list-skus --all to see whether the size is restricted. Only then does a retry make sense, rotating sizes in the same family. This example tries three sizes on an existing VM and skips the ones listed as restricted; az vm resize restarts the VM if it is running:
RG=my-rg; VM=my-vm; LOC=westeurope for size in Standard_D2as_v5 Standard_D2s_v5 Standard_D2ads_v5; do r=$(az vm list-skus -l $LOC --size $size --all \ --query "[?name=='$size'].restrictions[0].type" -o tsv) [ -n "$r" ] && { echo "$size restricted ($r), next"; continue; } az vm resize -g $RG -n $VM --size $size && break done What Control Cloud does with these errors
When a deploy fails, Control Cloud's error decoder turns SkuNotAvailable and QuotaExceeded into an explanation with the read-only command that confirms it (az vm list-skus and az vm list-usage). It does not recognize AllocationFailed or the core-quota OperationNotAllowed yet, and the pre-flight does not query Azure quota or SKUs before deploying: today that is what the commands in this note are for. To connect a subscription with read permissions, see the Azure guide and the note on the read-only service principal. If you want to try it, request access.
Sources
- Microsoft Learn, "Troubleshooting Azure VM allocation failures" (AllocationFailed, ZonalAllocationFailed, availability sets, zones, Overconstrained and older sizes).
- Microsoft Learn, "SKU not available errors" (SkuNotAvailable, InvalidTemplateDeployment,
az vm list-skus --all, Spot). - Microsoft Learn, "Resource Skus - List" API reference (restrictions: type Location or Zone, reasonCode, restrictionInfo.zones).
- Microsoft Learn, "vCPU quotas" (two tiers, quota and capacity checked separately, allocated and deallocated cores,
az vm list-usage) and "Resource quota errors" (OperationNotAllowed). - Microsoft Learn, "On-demand Capacity Reservation" (billed at the VM rate even when unused) and the
az postgres flexible-server list-skusreference. - In this repository: the backend error dictionary (errordict.go).
