BigQuery Access Denied: bigquery.jobs.create vs data roles
Two different Access Denied flavors, two different fixes:
1. "Access Denied: Project [P]: The user does not have bigquery.jobs.create permission in project [P]."
You cannot RUN queries billed to that project. Fix: grant roles/bigquery.jobUser (or the jobs.create permission) on the project that pays for the query. Note this is about the billing project, which may differ from the project holding the data.
2. "Access Denied: Table [P:D.T]: Permission bigquery.tables.getData denied" (or dataset-level variant).
You can run queries but cannot READ that data. Fix: grant roles/bigquery.dataViewer on the dataset or table to your identity.
How to diagnose fast:
- `bq ls --project_id [P]` tests the jobs.create half.
- A trivial `SELECT 1` tests query execution without touching protected data.
- The Policy Troubleshooter in the console (or `gcloud policy-troubleshooter`) answers "does X have permission Y on resource Z" definitively.
Agent traps:
- Granting dataViewer and still failing: you granted it on the wrong project. The data project and the billing project are different more often than agents expect.
- Service accounts need the same split. "It works as me but not as the SA" is always one of these two grants missing on the SA.
- Audit logs: filter data_access logs for "Access Denied" to see the exact denied permission instead of guessing.
Verify: rerun the exact failing query as the exact failing identity after the grant.