Skip to content

API errors

When a call to the Querri API fails, the response says why with an error code. Most of the errors below also carry a doc_url that links straight to the code on this page.

Errors come back wrapped in detail:

{
"detail": {
"error": {
"type": "invalid_request_error",
"code": "missing_tenant_id",
"message": "X-Tenant-ID header is required for API key authentication.",
"doc_url": "https://docs.querri.com/api/errors#missing_tenant_id"
}
}
}
FieldWhat it is
typeThe broad category, such as authentication_error, permission_error or rate_limit_error
codeThe specific error. Check this in your code rather than the message, which can change
messageA readable explanation
doc_urlA link to the code on this page. Not every error has one

access_denied and insufficient_permission also include resource_type and resource_id. Every response carries an X-Request-Id header, so quote it when you contact support.

This page covers the codes that link here. Errors about a specific item, such as source_not_found, are listed under Error codes in the Data API guide.

HTTP 401, authentication_error

The request had no credentials the API recognizes. It looks for an X-Embed-Session: es_... header, then an Authorization: Bearer qk_... API key, then a user’s token in Authorization: Bearer ey... or the access_token cookie. A Bearer value that starts with anything else ends up here too.

What to do: send your API key as Authorization: Bearer qk_..., with your organization ID in X-Tenant-ID. See Authentication.

HTTP 400, invalid_request_error

An API key was sent without the X-Tenant-ID header.

What to do: add X-Tenant-ID with your organization ID. It’s shown as Org ID on Settings → My Account.

HTTP 401, authentication_error

No key with that secret exists in the organization named in X-Tenant-ID. The key is mistyped, expired or revoked, or it belongs to a different organization.

What to do: check that the key and the organization ID belong together. If the key has expired or been revoked, an admin creates a new one in Settings → API Keys.

HTTP 401, authentication_error

Your bearer token didn’t validate. It has expired, it’s malformed or from the wrong issuer, or it’s missing the user (sub) or organization (org_id) claim.

What to do: sign in again for a fresh token (for the CLI, querri auth login). For jobs that run without a person, use an API key.

HTTP 401, authentication_error

The X-Embed-Session token doesn’t match a live session: it expired, was revoked or never existed. You also get this when Querri couldn’t renew the session’s sign-in, and in that case the session is revoked.

What to do: create a new session with POST /embed/sessions. POST /embed/sessions/refresh works only while the old session still exists. See Embed sessions.

HTTP 403, permission_error

Code running in a browser signed in to Querri tried to change something (POST, PUT, PATCH or DELETE) using the access_token cookie, and the X-CSRF-Token header was missing or didn’t match the csrf_token cookie.

What to do: set X-CSRF-Token to the value of the csrf_token cookie. See Cookie and CSRF. An integration that doesn’t run inside a Querri browser session should use an API key.

HTTP 403, permission_error

It’s the same check, from Querri servers that only look for the header: X-CSRF-Token wasn’t sent with a change made using the access_token cookie.

What to do: send X-CSRF-Token, set to the value of the csrf_token cookie, with every change.

HTTP 403, permission_error

This key only accepts requests from the addresses on its IP allowlist, and this one came from somewhere else.

What to do: call from an address on the list. The API can create and revoke keys but can’t change one, so to allow a new address, create a key that includes it and revoke the old key.

HTTP 403, permission_error

Your key doesn’t have the scope this endpoint needs. The message names the scope, or the scopes that would do.

What to do: use a key that has the scope, which usually means creating one. See Scopes. A user’s token gets its scopes from the user’s role, and an embed session has a fixed set. See JWT bearer tokens and Embed sessions.

HTTP 403, permission_error

The identity behind the request has no access to this item. For an API key, that’s the user the key is bound to, or the person who created the key if it isn’t bound. An ID that doesn’t exist gets this error too.

What to do: check the ID first. Then share the item with that person, or use a key tied to someone who can see it. If you’re sure the access is there, retry once, because a temporary fault while checking access also comes back as this error.

HTTP 403, permission_error

That identity can see the item but needs more access. The message names the level: editor for changes such as updating a project or adding rows to a source, and owner for deleting an item or changing who it’s shared with.

What to do: have the item shared with that person at the level the message names, or use a key tied to someone who already has it.

HTTP 503, service_unavailable_error

Querri couldn’t check your access at that moment. It’s a temporary problem on Querri’s side, not a change to your permissions. The response has a Retry-After: 5 header.

What to do: wait five seconds, then retry.

HTTP 429, rate_limit_error

Too many requests in the current minute. An API key’s limit is set when the key is created, 60 a minute by default. A user’s token allows 600 a minute per user, and an embed session 600 a minute per session.

What to do: wait for the Retry-After time (60 seconds), then spread your requests out. X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset show where you stand. The Python SDK and PHP SDK retry 429 for you. For a higher limit, create a key with a larger Rate Limit (per min).

HTTP 501, api_error

This endpoint exists but doesn’t work yet. These return it:

  • POST /dashboards
  • DELETE /dashboards/{dashboard_id}
  • POST /sources/{source_id}/sync
  • POST /dashboards/from-template and POST /dashboards/{dashboard_id}/export-template, without a doc_url

What to do: nothing in the request will fix it, so leave these calls out for now. The CLI’s dashboard new, dashboard delete and source sync call these endpoints and fail the same way, as do the matching SDK methods.