BigQuery connector¶
BigQuery is reached over the
jobs.query REST API with service-account authentication — no driver, no
SDK. A short-lived assertion signed with the service account's private key is
exchanged for an OAuth access token, which is cached and re-minted shortly
before it expires.
The API is stateless: every request carries its own default dataset, so USE
never persists between statements. Gated by exec-bigquery.
Experimental
The full executed-oracle corpus passes against a live project — 216 of 216 cases, no skips — alongside a smoke suite covering the type-decode matrix and multi-page results. Still experimental rather than preview: it is not yet in the nightly CI matrix, and results come back as rows rather than through a columnar read. See connector maturity.
Connection profile¶
datasources:
bigquery:
type: bigquery
project: ${BIGQUERY_PROJECT} # GCP project ID (or: catalog:)
dataset: ${BIGQUERY_DATASET} # default dataset (or: database:)
credentials_path: ~/.gcp/service-account.json
location: US # optional, e.g. US / EU
billing_project_id: quota-project # optional; defaults to project
The field names match the datus-bigquery adapter's, so one datasource entry
configures both datus-agent and Dosi.
Parameters¶
| Key | Type | Required | Default | Notes |
|---|---|---|---|---|
type |
string | yes | — | bigquery |
project |
string | yes | — | GCP project ID. Also spelled catalog: (Datus's name for this level); write one or the other, not both. |
dataset |
string | no | — | Default dataset, so a bare table name resolves. Also spelled database:; write one or the other. |
credentials_path |
path | one of the three | — | Path to a service-account JSON key file. |
credentials_info |
string | one of the three | — | The service-account JSON itself. Use ${VAR} — same rules as password, including the plaintext warning. |
credentials_base64 |
string | one of the three | — | The same JSON, base64-encoded, for secret stores that mangle newlines. |
location |
string | no | API default | Job location (US, EU, asia-northeast1, …). Required if your dataset is outside the API's default region. |
billing_project_id |
string | no | project |
Project the job is billed to and created in. |
default |
bool | no | false |
See connection profiles. |
Parsed and ignored on this connector: host, port, username,
password, uri (rejected outright), schema (also rejected — see
below), sslmode, sslrootcert, warehouse, role, arrow_flight_port,
compat_mode.
Authentication¶
Create a key for the service account and point credentials_path: at it:
$ gcloud iam service-accounts keys create ~/.gcp/service-account.json \
--iam-account=<name>@<project>.iam.gserviceaccount.com
The account needs bigquery.jobs.create on the billing project and read access
to the data. The assertion's issuer, audience and scope are derived from the key
file — nothing else to configure.
To keep the key out of the filesystem, pass its contents instead:
Exactly one of the three credential keys may be set. Two would mean two possible keys, and silently preferring one is how you authenticate as the wrong principal.
Application Default Credentials are not supported. A file written by
gcloud auth application-default login is an authorized_user credential,
which needs a refresh-token grant rather than the service-account JWT grant; the
connector rejects it by name rather than failing later on an opaque signing
error.
Two projects, not one¶
billing_project_id is where the job runs and is billed; project is where the
tables live. They are often the same, but a service account frequently may
create jobs only in its own project while reading another's. Getting them
backwards produces a permission error on job creation, not a missing-table
error:
Limitations¶
- No schema level. BigQuery's namespace is project → dataset, with nothing
below, so a
schema:key is rejected rather than silently ignored. Put the dataset indataset:(ordatabase:). - Row path only. Results come back as JSON and are pivoted into Arrow by the
shared normalizer. The columnar Storage Read API is not used yet; it is folded
into the planned generic
exec-adbcchannel. PRIMARY KEYandFOREIGN KEYin DDL must be declaredNOT ENFORCED, and BigQuery has noAUTO_INCREMENT,SERIAL, storageENGINE, orDISTRIBUTED BYclause — relevant if you run setup scripts through--execute.
Temporal and numeric values are handled for you. The API reports its legacy
type names (INTEGER, FLOAT, BOOLEAN — never the GoogleSQL INT64,
FLOAT64, BOOL you wrote in the DDL), renders TIMESTAMP as
scientific-notation epoch seconds, and pads DATETIME and TIME fractions out
to microseconds; all of these are normalized to the same form every other
connector produces. NUMERIC and BIGNUMERIC values too wide for a float stay
exact decimal text.
Verify the connection¶
$ dosi query --model model.yaml \
--metrics revenue --group-by orders.status --execute --connection bigquery
An authentication problem surfaces as an HTTP 401 or a token-endpoint error carrying Google's own message, which distinguishes a revoked key from a wrong project.
Troubleshooting¶
| Message | Cause and fix |
|---|---|
connection "x" (bigquery) needs project |
Set project: (or catalog:). |
connection "x" (bigquery) has no credentials |
None of credentials_path / credentials_info / credentials_base64 is set. ADC is not consulted. |
datasource "x" (bigquery) sets more than one of credentials_path, … |
Keep exactly one. |
connection "x": credentials are of type "authorized_user", not "service_account" |
An ADC file from gcloud auth application-default login. Export a service-account key instead. |
connection "x": credentials are not valid JSON / lack client_email / lack private_key |
Not a service-account key file, or a truncated copy. |
connection "x": bad service-account private key |
The private_key field is not a PKCS#8 PEM — unusual for a Google-issued key, and a sign the JSON was edited. |
datasource "x": credentials_info must be a string |
It was written as nested YAML. Use ${VAR}, or credentials_path. Rejected without echoing the value, so the key never reaches a log. |
datasource "x": bigquery has no schema level below a dataset |
Drop schema:. |
datasource "x": sets both "project" and "catalog" (or "dataset"/"database") |
Aliases — keep one. |
token endpoint returned no access_token: <msg> |
Clock skew beyond the assertion window, a disabled/deleted key, or a service account without the BigQuery scope. |
Access Denied: … does not have bigquery.jobs.create permission |
billing_project_id (or project) names a project the account cannot create jobs in. |
Not found: Dataset <p>:<d> |
Wrong dataset, or the dataset is in another location. |
BigQuery job did not finish within the poll budget |
A query slower than five minutes. Narrow it. |
bad BigQuery JSON: <e> |
The endpoint answered something unexpected, usually a proxy or an outage page. |
Reference¶
- Official site: https://cloud.google.com/bigquery
- API:
jobs.queryand service-account authorization - Also a stateless cloud API: Snowflake, Databricks
- Connection profiles