GitHub Actions OIDC to Google Cloud: "The given credential is rejected by the attribute condition"
GitHub gave the job a token, and Google Cloud's Security Token Service ran the workload identity provider's attribute condition, a CEL expression, on it. The expression came out false. Google does not say which part, so compare the condition with what the token says.
What it looks like
Error: google-github-actions/auth failed with: failed to generate Google Cloud federated token for //iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/github/providers/my-repo: {"error":"unauthorized_client","error_description":"The given credential is rejected by the attribute condition."}
"Failed to generate Google Cloud federated token" means the token was not let into the workload identity pool (the action's troubleshooting guide). The service account comes later, and a problem there has another message (see the end of this page).
Read the condition:
gcloud iam workload-identity-pools providers describe PROVIDER \ --project=PROJECT --location=global --workload-identity-pool=POOL \ --format='value(attributeCondition)'
1. The repository was renamed or transferred
A condition on names, such as assertion.repository_owner == 'old-org' or a workflow_ref that starts with the old name, stops matching when the repository moves. In univrse-onboardai #24, a transfer to another organization kept the repository ID but changed the owner ID, and both providers still pinned the old owner ID and the old workflow_ref.
The action's security notes recommend the numeric IDs, which GitHub never reuses. The repository ID stays the same through renames and transfers:
assertion.repository_id == '260064828' && assertion.ref == 'refs/heads/main'
gh api repos/OWNER/REPO --jq .id prints the repository ID; gh api orgs/ORG --jq .id prints an organization's. Add assertion.repository_owner_id only if the repository should stop working when it leaves the organization.
2. The condition checks sub, and sub now has IDs
From GitHub's changelog of April 23, 2026: repositories created after July 15, 2026, and renames and transfers after that date, use an immutable sub; older repositories only when someone opts in. A condition written against the old form matches nothing:
repo:octo-org/octo-repo:ref:refs/heads/main before repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main immutable
In fortaleza-game #7, a repository with use_immutable_subject: true failed against a provider that required the name form, and the fix was the condition above on repository_id and ref, which works with either form. To see which form a repository sends: gh api repos/OWNER/REPO/actions/oidc/customization/sub.
- An IAM binding to
principal://…/subject/repo:octo-org/octo-repo:…has the same problem one step later. AprincipalSet://…/attribute.repository_id/260064828binding withattribute.repository_id=assertion.repository_idin the mapping does not. - The immutable form is longer. If the mapping is
google.subject=assertion.sub, long names plus an environment can pass the 127-character limit Google Cloud sets forgoogle.subject.
3. A pull request, and the condition allows only main
A pull request run has ref refs/pull/N/merge, so assertion.ref == 'refs/heads/main' is false for it. That is usually intended: in olmo-eval #497, every pull request plan failed after the deploy identity was limited to main, and the project stopped authenticating from pull requests. If pull requests need read-only access, give them a separate provider or service account whose condition allows refs/pull/.
4. Capital letters
GitHub treats FooBar and foobar as the same name; Google Cloud does not, so the condition has to use the capitalization in the token (the action's troubleshooting guide).
See what the token says
The troubleshooting guide points to github/actions-oidc-debugger, which prints the claims. Run it in a private repository and compare repository, repository_id, repository_owner, ref and sub with the condition.
Telling it apart
- "Failed to generate Google Cloud OAuth 2.0 Access Token for" a service account: the token got into the pool, and impersonating the service account failed. Check the
roles/iam.workloadIdentityUserbinding and its principal. - "GitHub Actions did not inject $ACTIONS_ID_TOKEN_REQUEST_TOKEN or $ACTIONS_ID_TOKEN_REQUEST_URL into this job": there was no token to check: "Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable".
- The same immutable
subbreaks Azure and AWS trust too: "AADSTS700213" and "Not authorized to perform sts:AssumeRoleWithWebIdentity".
See failed jobs from IntelliJ IDEA
Pipeline Inbox for GitHub Actions Workflows, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, lists the runs of all your repositories in an IDE tool window, with their jobs and steps, and your current branch's runs are in the status bar. Reading is free; re-running failed jobs, cancelling, running workflows and reviewing deployments are Pro (US$1.50 a month, with a 30-day trial).
GitHub and GitHub Actions are trademarks of GitHub, Inc.; Google Cloud is a trademark of Google LLC; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with, sponsored or endorsed by GitHub, Inc., Google or JetBrains.
More: GitHub Actions OIDC to Azure · GitHub Actions OIDC to AWS · "Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable" · GitHub Actions plugins for IntelliJ IDEA compared · 日本語