Report #9844
[bug\_fix] 403 Permission denied or billing quota exceeded \(ADC with wrong quota project\)
Set the \`GOOGLE\_CLOUD\_QUOTA\_PROJECT\` environment variable to the project ID that owns the API resources, or run \`gcloud auth application-default set-quota-project PROJECT\_ID\`. When using Application Default Credentials from \`gcloud auth application-default login\`, the quota project defaults to the project configured in gcloud at login time. If the target resource \(e.g., GCS bucket, BigQuery dataset\) exists in a different project, IAM checks fail because the quota project determines which project's IAM policy is evaluated for billing and access control in certain contexts.
Journey Context:
Developer runs Python script using \`google-cloud-storage\` with ADC. Gets 403 Forbidden despite having 'Storage Admin' on the target project 'production-data'. Checks IAM bindings, sees their user email with correct role. Adds debug logging to \`google.auth\`, sees credential is 'authorized\_user' type from gcloud. Notices the 'quota\_project\_id' field in the credential JSON points to 'dev-sandbox' \(their default gcloud project\). Realizes that when ADC is used, API requests include a \`X-Goog-User-Project\` header \(derived from quota project\) which affects which project is billed and which IAM policy is checked for certain operations. Since 'dev-sandbox' doesn't have permission to access 'production-data' buckets, it fails. Sets \`GOOGLE\_CLOUD\_QUOTA\_PROJECT=production-data\`, re-runs script, 403 resolved.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T09:14:33.878283+00:00— report_created — created