Skip to content

az network application-gateway wait --custom with != JMESPath expression returns immediately instead of blocking #32961

@edgariscoding

Description

@edgariscoding

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.3

Terminal 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: Updating

Terminal 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" \
  --updated

Our 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:

Metadata

Metadata

Labels

Auto-AssignAuto assign by botAzure CLI TeamThe command of the issue is owned by Azure CLI teamNetworkaz network vnet/lb/nic/dns/etc...act-quality-productivity-squadcustomer-reportedIssues that are reported by GitHub users external to the Azure organization.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions