ExpressRoute circuit billing with no carrier connection
An ExpressRoute circuit whose connectivity provider has not provisioned it, so it bills the full monthly port fee while carrying no traffic.
Why it happens
Azure bills an ExpressRoute circuit from the moment the service key is issued, not from the moment the carrier connects it, and billing stops only when the circuit is deleted. A circuit left in NotProvisioned is the classic ordered-and-forgotten case: somebody created it ahead of the carrier, the order stalled, and the port fee has been charged ever since. Deprovisioning is the same position from the other end, where the provider has released the circuit and it keeps billing until it is removed. Ports start at $55 a month for Standard Metered 50 Mbps and reach thousands at 10 Gbps.
Paste this into Resource Graph Explorer in the Azure portal.
resources
| where type =~ 'microsoft.network/expressroutecircuits'
// Scope below matches CloudFinOpsPro policy DEFAULTS: exclusions.protectTag, environment.tagKeys,
// environment.allowedTagValues, and allowUntagged false so an untagged resource counts as production.
// If your policy.yaml differs, edit the three lines below or this will disagree with your own agent.
| where tolower(tostring(coalesce(tags['cfop:protect'], ''))) !in ('true', 'yes', '1')
| extend cfopEnv = tolower(trim(' ', tostring(coalesce(tags['Environment'], tags['environment'], tags['env'], ''))))
| where cfopEnv in ('dev', 'development', 'test', 'qa', 'sandbox', 'nonprod', 'non-prod', 'staging')
| extend providerState = tostring(properties.serviceProviderProvisioningState)
| where tolower(providerState) in ('notprovisioned', 'deprovisioning')
| project name, resourceGroup, location, providerState, sku = tostring(sku.name), environment = cfopEnvA circuit bills its port and bandwidth from the moment it exists. serviceProviderProvisioningState is an enum of NotProvisioned, Provisioning, Provisioned and Deprovisioning, and the two matched here mean the carrier never completed the circuit or is tearing it down, so it is charging for a connection carrying no traffic. Both are matched lower-cased because the enum casing is not guaranteed. This is a structural test, so what it returns is what the check reports.
Applies to microsoft.network/expressroutecircuitsWhat the agent does about it
An ExpressRoute circuit whose connectivity provider has not provisioned it, so it bills the full monthly port fee while carrying no traffic.
It will not fix this one
It reports this and takes no action. A check only earns the right to change something once the action behind it can re-read live state before it fires and knows the way back.