-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Describe the bug
az network application-gateway wait --custom "provisioningState!='Updating'" returns immediately (~2 seconds) even while the gateway's provisioningState is Updating. The JMESPath != expression does not evaluate correctly — it always passes, regardless of the actual state.
The built-in --updated flag works correctly and blocks for the full duration of the operation. This means provisioningState is accurate, but --custom with a != expression fails to evaluate it properly.
Side-by-side proof during the same gateway update operation:
| Method | Gateway state | Behavior | Duration |
|---|---|---|---|
--custom "provisioningState!='Updating'" |
Updating |
Returned immediately (broken) | ~2s |
--updated |
Updating |
Blocked until operation completed (correct) | ~47s |
az appgw show --query provisioningState |
Updating |
Correctly returned "Updating" |
N/A |
Impact: This bug makes it impossible to use --custom as a pre-flight check to coordinate concurrent updates. We used this in CI/CD pipelines to avoid CanceledAndSupersededDueToAnotherOperation errors when multiple pipelines update different backend pools on the same gateway. Because --custom always returned immediately, every pipeline blew through the wait and collided.
Related command
az network application-gateway wait --custom
Errors
No error is raised — --custom silently returns a false positive. The downstream consequence is that a second pipeline submits while the first is still in progress, causing:
(CanceledAndSupersededDueToAnotherOperation) Operation PutApplicationGatewayOperation
was canceled and superseded by another PutApplicationGatewayOperation.
Code: CanceledAndSupersededDueToAnotherOperation
Issue script & Debug output
Reproduction requires two terminals and one App Gateway.
Terminal 1 — trigger a real pool update (must make an actual change):
az network application-gateway address-pool update \
--gateway-name "agw-example" \
--resource-group "rg-example" \
--name "my-api-pool" \
--servers 10.0.1.1 10.0.1.2 10.0.1.3Terminal 2 — while Terminal 1 is running (~10 seconds in), run the --custom wait:
# This should block but returns in ~2 seconds (BUG)
az network application-gateway wait \
--name "agw-example" \
--resource-group "rg-example" \
--custom "provisioningState!='Updating'" \
--interval 5 \
--timeout 120
# Immediately after, confirm the gateway is still Updating
az network application-gateway show \
--name "agw-example" \
--resource-group "rg-example" \
--query "provisioningState" -o tsv
# Returns: UpdatingTerminal 3 — for comparison, run --updated at the same time:
# This correctly blocks for ~50 seconds
az network application-gateway wait \
--name "agw-example" \
--resource-group "rg-example" \
--updatedOur test results (PowerShell, local machine polling every 2 seconds):
We ran a monitoring script that polled az appgw show --query provisioningState every 2 seconds while triggering a pipeline that called az address-pool update. The show command correctly returned Updating for ~59 seconds during the operation.
We then ran a second test that detected Updating via the show poll, immediately launched --custom "provisioningState!='Updating'", and it returned in ~2 seconds while show still reported Updating:
[16:48:16.121] *** UPDATING DETECTED (via show) ***
=== Test A: --custom "provisioningState!='Updating'" ===
[16:48:19.978] --custom returned after 2s
provisioningState right after --custom returned: Updating
*** BROKEN: --custom returned while gateway is still Updating! ***
In a separate test, --updated blocked correctly for ~47 seconds until the operation completed.
Debug output from the --custom call shows it performs a GET, receives the full gateway JSON, and exits with code 0 after a single poll — suggesting the JMESPath expression evaluates to a truthy value even when provisioningState equals Updating.
Expected behavior
az network application-gateway wait --custom "provisioningState!='Updating'" should block while provisioningState is Updating and only return once the condition is actually true (i.e., when provisioningState changes to Succeeded).
The != JMESPath expression should evaluate to false when the property equals the compared value, just as the == expression (used internally by --updated) correctly evaluates to false when the property does not match.
Environment Summary
azure-cli 2.84.0 (mcr.microsoft.com/azure-cli:2.84.0, Linux)
azure-cli 2.70.0 (Windows, local testing)
Both versions exhibit the same behavior.
Additional context
Workaround: Use --updated instead of --custom "provisioningState!='Updating'". The --updated flag correctly checks provisioningState=='Succeeded' internally and blocks for the full duration of an in-progress operation.
This bug may not be specific to Application Gateway — any resource where --custom uses a != JMESPath expression against provisioningState may be affected. We have not tested other resource types.
Related issues:
- Application Gateway - CanceledAndSupersededDueToAnotherOperation issue #21156 —
CanceledAndSupersededDueToAnotherOperationduring concurrent App Gateway updates - Update to application gateway address pool reverts unrelated previous app gateway address pool update #27771 — Concurrent pool updates silently revert each other's changes