Fix a permission denial on Google Cloud — the order to check things in
Seven steps, in the order that answers fastest: read the three facts off the error, retry once for eventual consistency, run Policy Troubleshooter, rule out deny and boundary policies, check whether the permission needs actAs, then grant the narrowest predefined role. Ends with the three things never to do.
markdownguidev1MHSM-NJWZstage: operatetrust: officialfamily: identityservice: iaminterface: clipermission denied403access deniedpolicy troubleshooteractAsdeny policyiam bindingadd-iam-policy-binding
Fix a permission denial
Step 1 — read three facts off the error, then retry once
A Google Cloud permission error carries an error ID whose context is "the principal, resource, permission". Those three are the whole input to every step below. Write them down before you touch a policy.
Then retry the identical call once. The IAM API is eventually consistent and a recent grant "might take time to affect access checks". A single retry costs nothing and resolves a measurable share of denials with no change at all.
Step 2 — ask the platform why, instead of guessing
gcloud beta policy-intelligence troubleshoot-policy iam RESOURCE \
--principal-email=EMAIL --permission=PERMISSION
PERMISSION is the service.resource.verb string from the error, not a role. The tool evaluates allow
policies, deny policies and Principal Access Boundary policies together, which is the only way to see an
interaction between them.
If the answer is Unknown, stop. It means the principal running the diagnosis cannot read one of the
policies involved. It does not mean the policy is absent. Re-run as a principal that can read the
organization's policies.
Step 3 — is a role missing, or is one being cancelled?
The page's rule: "all policy types must permit access." So there are two different repairs and they look the same from the caller's side:
| Troubleshooter says | Repair |
|---|---|
| no allow policy grants it | add a role binding (step 6) |
| a deny policy blocks it | the binding will not help — deny overrides allow. The deny policy must change, and that is almost always somebody else's decision |
| a Principal Access Boundary makes the resource ineligible | same: an outer policy, not yours to widen |
| a conditional binding evaluated false | read the condition. The usual causes are a time window, a resource-name prefix, or a tag the resource does not carry |
| group membership unverifiable | the principal is in a group the evaluator cannot resolve; bind the principal directly to test, then fix the group |
Three of those five are refusals working as intended. Widening them is operator-hand work, not a fix.
Step 4 — check the inherited grants before you add one at the leaf
Policy inherits down the hierarchy: organization → folder → project → resource. A principal may already hold the role one level up, in which case your failure is not the one you think it is. Look upward before adding a binding at the leaf — and remember that nothing at a child level can take a parent's grant away.
Step 5 — the actAs class, which is not a missing role on the resource
If the permission in the error is about a service account rather than about the resource you were touching
— anything of the iam.serviceaccounts.* shape — the denial is about identity attachment:
| You are trying to | Role the caller needs |
|---|---|
| create a resource that runs as a service account | roles/iam.serviceAccountUser on that service account |
| mint a credential as a service account | roles/iam.serviceAccountTokenCreator on it |
They are different grants on a different object (the service account's own allow policy, not the project's). A Cloud Run deploy failing with "User does not have permission to access namespace" is usually this.
Step 6 — grant the narrowest predefined role, at the narrowest scope
Find the role that carries the permission (reference/identity/predefined-roles-and-permissions.md), then bind
it as low in the hierarchy as the caller's work allows — on the bucket, not the project; on the project, not
the folder.
Step 7 — confirm, and record what it was
Re-run the original call. Then record which permission was missing: a migration estimate's accuracy depends
on this list existing (guides/parity-and-migration-method.md uses it as an input).
Never
- Never grant a basic role (
Owner,Editor,Viewer) to close a denial. The IAM overview calls them
"highly permissive, unsuitable for production" and they grant every service rather than the one that failed.
- Never write the policy twice on the first failure. The second read-modify-write on a stale
etagis how
an unrelated binding disappears.
- Never answer a 401
authErrorwith a role grant. That one is the credential, not the policy.