Identity error catalogue — access denied, actAs, quota refusals, and the one tool that answers "why"

Cause, check and fix for the refusals that come from IAM rather than from the service being called. Includes the Policy Troubleshooter command verbatim, the five-way policy evaluation that decides a denial, the eventual-consistency false alarm, and the fixed limits that look like bugs.

markdownreferencev1HBJ7-0Z5Tstage: operatetrust: officialfamily: identityservice: iaminterface: anyaccess deniedpermission denied403forbiddeninsufficientPermissionsauthErroractAsPolicy Troubleshooterdeny policyprincipal access boundaryeventual consistency

Created 21 Oct 2026 · Modified 23 Oct 2026 · 1 version

Identity error catalogue

Every row is cause → check → fix. The check is what confirms the cause; run it before changing a policy.

1. The refusals

SignatureCauseCheckFix
HTTP 403, reason forbidden — "According to access control policy, the current user does not have access"the allow policy does not grant a role carrying the permissionrun Policy Troubleshooter (§2) with the exact permission from the errorgrant the predefined role that carries it (reference/identity/predefined-roles-and-permissions.md), at the narrowest resource that works
HTTP 403, reason insufficientPermissionsas above, with the service reporting it per-action rather than per-resourcesamesame
HTTP 401, reason authErrorthe credential itself: the token is expired or its format is not recognisedre-mint the credential; if the caller federates, confirm the exchange still returns a tokenfix the credential path, not the policy — a 401 is never answered by a role grant
A permission error carrying an error IDthe service is telling you which principal, which resource and which permissionthe ID "provides context for the error, including the principal, resource, permission" — read all three off itthe three facts are the whole input to Policy Troubleshooter
"User does not have permission to access namespace" on a Cloud Run deploythe deployer cannot act as the runtime service account, or the default Compute Engine service account has been deletedcheck whether the deployer holds roles/iam.serviceAccountUser on the runtime account, and whether that account still existsgrant roles/iam.serviceAccountUser (not TokenCreator) and pass --service-account explicitly
HTTP 429, reason rateLimitExceededa usage limit, not a permissionread the live quota (reference/overview/quotas-and-limits-model.md)back off with truncated exponential backoff, then request an increase if it is adjustable
A grant that "did not work", and works a minute laternot an error. The IAM API is eventually consistent; a change "might take time to affect access checks"retry the original call once, unchangedwait. Do not write the policy again — a second read-modify-write on a stale etag is how a binding gets lost

2. The one tool that answers "why", verbatim

gcloud beta policy-intelligence troubleshoot-policy iam RESOURCE \
    --principal-email=EMAIL --permission=PERMISSION

It evaluates every policy type that bears on the call. The page's own rule is the one to hold on to:

"For a user to be able to use the permission to access the resource, all policy types must permit access."

3. The five things it checks, in the order a denial is decided

  1. a Principal Access Boundary policy makes the resource ineligible;
  2. a deny policy blocks the permission — and deny overrides allow, so this outranks any role the principal

holds;

  1. the allow policies simply do not carry the permission;
  2. a conditional role binding exists and its condition evaluated false;
  3. group membership could not be verified.

A sixth outcome is the troubleshooter's own: "Unknown", when the caller running it lacks permission to read one of the policies involved. An Unknown is not a pass. It means you need a higher-privileged principal to run the diagnosis, and treating it as "no deny policy found" is the single most common misread.

4. Limits that present as errors

Each of these is fixed; the IAM quotas page states, verbatim, "Limits cannot be changed." A call failing against one of them is not a quota you can raise.

LimitValueHow it shows up
principals in one allow policy1,500adding a binding starts failing on a mature project; the fix is groups, not retries
deny policies per resource500a policy-as-code rollout stops applying
custom roles per project / per organization300 eacha generated-role pipeline stalls
service account keys per account10a key rotation that creates before deleting fails on the 11th
maximum access token lifetime3,600 s, extendable to 12 h by organization policya long job dies mid-run; lengthen the lifetime by policy or re-mint

5. Where to go next

  • the order to check things in: guides/identity/fix-permission-denied.md
  • the keyless setup that removes a whole class of 401s:

guides/identity/github-actions-without-keys.md

  • the same refusals' AWS and Azure counterparts, and why a migrated workload hits different ones:

guides/parity/identity.md

Read this document as markdown — the same bytes an agent receives.