Docs/Error messages/Access Denied: no permission to query table
Error messagesPermissions

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

  1. Spelling and case. Dataset and table names are case-sensitive, so SAMPLES is not samples. A project id with a typo produces this error too.
  2. The billing project. If you switched projects, you may have lost bigquery.jobs.create.
  3. Whether the grant is on the table or on the dataset. A grant on one table does not cover the others.
  4. Views. Reading a view requires access to its underlying tables, unless it is an authorized view.
  5. 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 (SAMPLES instead of samples)
  • 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.create on the project the query is billed to, usually from roles/bigquery.jobUser. This is about where the job runs, not where the data lives.
  • bigquery.tables.getData on every table and view the query references, including tables behind a view, usually from roles/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

MessageCause
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 tagcolumn-level security
Access denied: Requires fineGrainedGet permission on the read columns to execute the DML statementscolumn-level security hit by a DELETE, UPDATE or MERGE
Access Denied: Reservation projects/.../reservations/NAME: Permission bigquery.reservations.use deniedSET @@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.