## TL;DR

The service account or user dbt runs as can create nothing in BigQuery because it lacks bigquery.jobs.create on the project. Grant roles/bigquery.jobUser (or a custom role containing jobs.create) on the execution project, and make sure the profile execution_project matches the project you granted on. dbt can then submit jobs.

```text
dbt-bigquery: 403 Access Denied: User does not have bigquery.jobs.create permission
```

## Use this when

- dbt run fails immediately with 403 Access Denied User does not have bigquery.jobs.create permission
- the error names the project dbt submits jobs to
- you switched service accounts, projects, or moved from user credentials to a service account

## Not for this skill when

- jobs are created but fail reading a source dataset, that needs bigquery.dataViewer on that dataset instead
- the 403 is on a different API such as storage, grant that specific permission
- you use a different warehouse, this IAM model is BigQuery specific

## Steps

1. Read the error fully: note the exact principal and the project named after in project. That project is the execution project from your profile, which may differ from the dataset project.
   Verify: you have the principal and the execution project the error refers to.

2. In Google Cloud IAM for that project, check the principal roles. Confirm whether roles/bigquery.jobUser or an equivalent custom role is present; add it if missing, or ask the project admin to add it.
   Verify: IAM shows the principal with a role containing bigquery.jobs.create on that project.

3. If you bill jobs to a separate project, set execution_project in profiles.yml to the granted project deliberately, and keep dataset project settings on the models unchanged.
   Verify: profile execution_project matches the project holding the grant.

4. Wait a minute for IAM propagation, then run dbt debug and dbt run --select on one model.
   Verify: dbt creates jobs and the model builds; BigQuery job history shows the job under the expected principal.

## Variant phrasings

### user credentials work, service account fails
Developers often test with their own account, which has broad roles. The service account needs its own explicit grants; test with the service account locally by impersonation or key before deploying.

### 403 names a project you do not recognize
A stale GOOGLE_CLOUD_PROJECT environment value or an old profile output can redirect jobs. Print the resolved profile with dbt debug.

Compatibility: dbt-bigquery 1.x with Google Cloud IAM. jobs.create is included in roles/bigquery.jobUser and roles/bigquery.user; grants are per project.

## Why it happens

Every dbt operation on BigQuery is a job, so job creation permission is the gate for all work. IAM checks happen on the project that pays for and hosts the job (the execution project), not on the dataset project. A missing jobs.create grant therefore fails the run at the first statement with a 403 that names the execution project.

## Edge cases / pitfalls

- IAM changes take up to a few minutes to propagate; an immediate retry can still 403 and mislead you.
- Granting dataViewer on datasets does not include jobs.create; the two most common BigQuery grants solve different errors.
- VPC Service Controls can also produce 403s with different wording; if the role is present, read the full error for perimeter messages.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Mhz-ZGzjcn2wgXOMoTnDBA
