Access Denied: User does not have permission to query table
BigQuery sends this one message for a missing permission, a misspelled dataset, a dataset in the wrong case and a project that does not exist. Why it refuses to say which, and the order to check things in.
Access Denied: Table other-project:their_dataset.events: User does not have permission to query table other-project:their_dataset.events, or perhaps it does not exist.
What to check, in order
- Spelling and case. Dataset and table names are case-sensitive, so
SAMPLESis notsamples. A project id with a typo produces this error too. - The billing project. If you switched projects, you may have lost
bigquery.jobs.create. - Whether the grant is on the table or on the dataset. A grant on one table does not cover the others.
- Views. Reading a view requires access to its underlying tables, unless it is an authorized view.
- Column-level security. A policy tag on a column produces a different message that names the tag.
What BigQuery means
Read the end of the sentence literally. BigQuery is saying it will not tell you which of the two it is.
You get this exact text in all of these cases:
- the table exists and you cannot read it
- the dataset exists and you cannot read it, so the table was never looked up
- the dataset name is misspelled
- the dataset name has the wrong case (
SAMPLESinstead ofsamples) - the project does not exist at all
That is deliberate. Confirming that finance.salaries exists would leak something to a person
who has no access to it, so BigQuery collapses “no” and “not allowed” into one answer.
The flip side is useful. If you get Not found: Table ... was not found in location ...
instead, you have been told the table is absent, which means you can read the dataset. See
Not found: Table was not found in location
for the full decision table.
Note the separator. BigQuery prints the reference as project:dataset.table with a colon,
while you write it with a dot.
Two separate permissions
A query needs both, and the error does not say which one is missing:
bigquery.jobs.createon the project the query is billed to, usually fromroles/bigquery.jobUser. This is about where the job runs, not where the data lives.bigquery.tables.getDataon every table and view the query references, including tables behind a view, usually fromroles/bigquery.dataViewer.
The second one is the usual cause when a query that worked for a colleague fails for you. The
first one is the usual cause when a service account is involved. Running against someone
else’s shared dataset still needs bigquery.jobs.create in your own project.
Ask for the roles, not the permissions. Nobody can grant you bigquery.tables.getData on its
own. If you own the dataset, one statement does it:
GRANT `roles/bigquery.dataViewer`
ON SCHEMA `my-project.analytics`
TO "user:[email protected]"
If you do not own it, ask its owner for roles/bigquery.dataViewer on the dataset and your
own admin for roles/bigquery.jobUser on your project. See
Access control.
Variants
| Message | Cause |
|---|---|
Access Denied: Project PROJECT_ID: User does not have bigquery.jobs.create permission in project PROJECT_ID. | no permission to run a job in the billing project |
Access Denied: Dataset PROJECT:DATASET: Permission bigquery.datasets.get denied on dataset PROJECT:DATASET (or it may not exist). | a metadata read, not a query, against a dataset you cannot see |
Access Denied: BigQuery BigQuery: User does not have permission to access data protected by policy tag | column-level security |
Access denied: Requires fineGrainedGet permission on the read columns to execute the DML statements | column-level security hit by a DELETE, UPDATE or MERGE |
Access Denied: Reservation projects/.../reservations/NAME: Permission bigquery.reservations.use denied | SET @@reservation without bigquery.reservations.use |
IAM setPolicy failed for Dataset DATASET: Operation denied by org policy on resource. | an organization policy, not an IAM grant |
The job’s error_result.reason for all the query cases is accessDenied. You can read it with
bq show -j JOB_ID or from INFORMATION_SCHEMA.JOBS.
In Querylab.io
Querylab.io dry-runs the query as you type, so BigQuery’s message appears in the editor for free, before you run anything.
See also Projects, datasets and tables.