google-github-actions/upload-cloud-storage "bucket not found"
The action uploads to a named GCS bucket using the authenticated service account. A wrong name, wrong project, or unauthorized account resolves as bucket not found.
What this error means
The upload step fails with "bucket doesn't exist" or a 404/403 on the bucket.
Error: failed to upload: storage: bucket doesn't exist
##[error]googleapi: Error 404: Not Found, notFoundDiagnose it: what token do you actually have?
Permission failures in Actions are almost never about your repository settings alone. Three things combine: the default GITHUB_TOKEN permission set for the repo or organization, the permissions: block in the workflow, and whether the event is a fork pull request, which downgrades the token to read-only regardless of everything else.
- name: Show the token scopes actually granted
run: |
curl -sI -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/ | grep -i "^x-oauth-scopes\|^x-accepted"
echo "event: ${{ github.event_name }}"
echo "fork PR: ${{ github.event.pull_request.head.repo.fork }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Common causes
Wrong bucket name
A typo or environment mismatch points at a bucket that does not exist.
Service account lacks access
The authenticated account cannot see the bucket, which surfaces as not found.
Wrong project context
Auth resolved to a different project that does not contain the bucket.
How to fix it
Authenticate, then target the correct bucket
- Run google-github-actions/auth before the upload.
- Set the destination to the exact existing bucket name.
- Grant the service account storage.objectAdmin on that bucket.
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ci@my-project.iam.gserviceaccount.com
- uses: google-github-actions/upload-cloud-storage@v2
with:
path: dist
destination: my-existing-bucket/buildsGrant the narrowest permission that works
Declaring a permissions: block switches the job from the repository default to exactly what you list, so an incomplete block is a common cause of a new failure right after someone tightened security. List every scope the job needs, not just the one that failed.
permissions:
contents: read # checkout
packages: write # push to GHCR
id-token: write # OIDC to a cloud provider
pull-requests: write # comment on or label a PR
checks: write # publish check runsHow to prevent it
- Parameterize bucket names per environment to avoid pointing dev at a prod bucket.
- Grant the CI service account explicit access to the target bucket.