Managed identity errors and delays
Look up a managed identity failure — IMDS status codes (400 bad_request_102, invalid_resource, 404, 410, 429, 5xx), "identity hasn't been assigned", unauthorized_client, proxies in front of IMDS, App Service and Container Apps endpoint variables missing, a 403 from the target after a role or group change, a VM that won't start after a move, identities broken by a tenant transfer, and 409 on federated credentials — with cause, check and fix.
markdownreferencev1GCZK-E5VMstage: operatetrust: officialservice: managed-identityinterface: anymanaged identity errorIMDS errorbad_request_102Required metadata header not specifiedinvalid_resource AADSTS50001 IMDSunauthorized_client managed identityIMDS 404 410 429The requested identity hasn't been assigned to this resourceIDENTITY_ENDPOINT missingmanaged identity 403 after role assignmentmanaged identity group membership not appliedmanaged identity token cache 24 hoursVM fails to start after move managed identitysubscription transfer managed identity brokenmultiple user-assigned identities
Two different things fail. Getting the token (the host's endpoint refuses or doesn't answer) fails with the errors in the first table. Using the token (the target service answers 401 or 403) is a role problem, and for managed identities often a delay problem: the second table. SDK wording for the same failures is in reference/azure-identity/errors.md.
Getting the token
On a VM the endpoint is IMDS, http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=<resource> with header Metadata: true. The response body has error and error_description; don't branch on the description, which changes.
| Response | Cause → fix | Check |
|---|---|---|
400 bad_request_102 Required metadata header not specified | The Metadata: true header is missing or not lower-case true | The raw request |
400 invalid_resource AADSTS50001: The application named <URI> wasn't found in the tenant… | The resource value is wrong (typo, or a URI not registered in this tenant) | Compare with the service's resource, such as https://management.azure.com/ |
400 The requested identity hasn't been assigned to this resource. (SDK wording) | The client ID asked for isn't attached, or system-assigned is off | az vm identity show --name <vm> --resource-group <rg> |
| 400 with several user-assigned identities and none chosen | Pass client_id, object_id or msi_res_id (SDK: clientId or resourceId) | Same call lists more than one |
401 unauthorized_client | Managed identity isn't configured correctly on the VM | Same call |
| 404 / timeout | IMDS is updating: retry with exponential backoff | Retry succeeds |
| 410 | IMDS is updating and is back within 70 seconds | Retry after 70 s |
| 429 | IMDS throttled you. Cache tokens (they're valid 24 hours; refresh 5 minutes before expires_on) instead of fetching per call | Count token requests per minute in your code |
500 Failed to retrieve token from the Active directory / other 5xx | Transient; retry after at least 1 second, with backoff | Retry succeeds |
| 502 / 504, or nothing answers | A proxy is between the app and 169.254.169.254. IMDS behind a proxy isn't supported: exclude it from the proxy | echo $HTTP_PROXY $NO_PROXY |
| App Service, Functions, Container Apps: no endpoint | IDENTITY_ENDPOINT and IDENTITY_HEADER aren't set because no identity is enabled. (Microsoft's SDK guide still names the older MSI_ENDPOINT / MSI_SECRET.) | az webapp identity show --name <app> --resource-group <rg> (containerapp, functionapp the same) |
Using the token
| Symptom | Cause → fix | Check |
|---|---|---|
| 403 from the target, role was just assigned | Azure RBAC changes take up to about 10 minutes to apply | az role assignment list --assignee <principalId> --all; retry after 10 minutes |
| 403 for hours after adding the identity to an Entra group (or app role) | Group and role claims ride in the token, and managed identity tokens are cached about 24 hours per resource; the refresh can't be forced | Assign the role directly to the identity (Microsoft's recommendation), or wait out the cache |
| 403 at a management-group scope for a data action | Built-in roles with DataActions at management-group scope can take hours to reach the data plane | Assign at subscription or lower scope |
| 403, role is assigned to an identity | The code used another identity (system- vs user-assigned, or the wrong client ID) | Log the authenticated account (reference/azure-identity/credential-chain.md) and compare its object ID with principalId |
| 403 with Owner or Contributor | Those are control-plane roles; data needs the service's data role (for example Key Vault Secrets User) | az role assignment list --assignee <principalId> --all --query "[].roleDefinitionName" |
Lifecycle
| Symptom | Cause → fix | Check |
|---|---|---|
| A VM moved (resource group or subscription) while running won't start after it's stopped | The VM keeps a stale identity reference. Microsoft's workaround is updating the VM (adding and removing a tag such as fixVM) so the identity reference refreshes | Was the VM moved since its last start? |
| Every managed identity fails after a subscription moved to another tenant | Identities don't follow a tenant transfer. Re-create user-assigned identities and re-attach them; disable and re-enable system-assigned ones; re-create role assignments (the transfer deletes them) | az account show --query tenantId vs the identity's tenantId |
| Role assignment shows Identity not found | The identity was deleted (or recreated with a new principal ID) without removing its assignment | az role assignment list --scope <scope> → empty principalName |
| 409 creating federated credentials on one identity | Created in parallel; create them serially | reference/entra/federated-credential-errors.md |
When none of these fits
Call the endpoint by hand from the host (curl -H Metadata:true "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F" on a VM). Its output contains a live token, so don't paste it anywhere. If that works and your code doesn't, the problem is which identity the code selects.