# Bonnard errors and how to fix them

> The errors that app URLs, sign-in and tool calls return, each with its exact message, its cause, the fix and a stable link.

Updated: 2026-10-15

This page gives the errors that Bonnard sends to AI clients, scripts and the people who sign in. Each entry quotes the
message exactly, where there is one, then gives the cause and the fix. Your database's own errors are on its connector page.

Verified 15 Oct 2026.

## At a glance

Table: Each error, where it shows and its cause

| Error | Where | Cause |
| --- | --- | --- |
| [`Method not allowed.`](#method-not-allowed) | App URL, HTTP 405 | The request is not a POST |
| [`not_found`](#not_found) | App URL, HTTP 404 | No app at this URL, or the app is not published |
| [`unauthorized`](#unauthorized) | App URL, HTTP 401 | No access token or API key |
| [`invalid_token`](#invalid_token) | App URL, HTTP 401 | The token or key does not work for this URL |
| [`forbidden`](#forbidden) | App URL, HTTP 403 | The staging URL, for someone outside your workspace |
| [`server_misconfigured`](#server_misconfigured) | App URL, HTTP 500 | Bonnard cannot load the app |
| [`batch_too_large`](#batch_too_large) | App URL, HTTP 400 | More than 100 requests in one batch |
| [`audience_forbidden`](#audience_forbidden) | App URL, HTTP 403 | The caller is not in the app's audience |
| [`no_test_context`](#no_test_context) | App URL, HTTP 409 | Staging cannot select a customer to act as |
| [`no_tenant`](#no_tenant) | App URL, HTTP 403 | The caller has no tenant (the value that marks a customer's data in your database) |
| [`not_serving`](#not_serving) | App URL, HTTP 402 | The workspace that owns the app must act first |
| [`payment_failed`](#payment_failed) | App URL, HTTP 402 | A payment failed and the grace period ended |
| [`allowance_exhausted`](#allowance_exhausted) | App URL, HTTP 402 | No calls left in the plan for this period |
| [`no_payment_method`](#no_payment_method) | App URL, HTTP 402 | Extra usage with no payment method on file |
| [`spend_limit_reached`](#spend_limit_reached) | App URL, HTTP 402 | The workspace reached its spend limit for this period |
| [`tenant_id_invalid`](#tenant_id_invalid) | App URL, HTTP 403 | A SQL Server tenant of more than 128 characters |
| [`no_tenant_credential`](#no_tenant_credential) | App URL, HTTP 403 | No service account for this tenant |
| [`tenant_not_routable`](#tenant_not_routable) | App URL, HTTP 403 | No dataset, database or schema for this tenant |
| [`access_denied`](#access_denied) | AI client, after sign-in | The sign-in ended with no access |
| [`rate_limited`](#rate_limited) | Sign-in, HTTP 429 | Too many requests in a short time |
| [Expired authorization request](#expired-authorization-request) | Authorize page | The sign-in request is too old |
| [`That code is invalid or expired.`](#that-code-is-invalid-or-expired) | Sign-in page | A wrong or old email code |
| [No code arrives](#no-code-arrives) | Sign-in page | Bonnard sent no email code |
| [`We could not continue this sign-in.`](#we-could-not-continue-this-sign-in) | Sign-in page | The sign-in request failed |
| [Single sign-on fails](#single-sign-on-fails) | Sign-in page | The customer's identity provider did not sign the person in |
| [`invalid_arguments`](#invalid_arguments) | Tool result | The agent sent arguments that the tool does not take |
| [Read-only refusals](#read-only-refusals) | Tool result | The SQL is not one read-only query |
| [`Table '<name>' is not exposed.`](#table-name-is-not-exposed) | Tool result | No such table on this app |
| [Database permission errors](#database-permission-errors) | Tool result | The database user cannot run the query |
| [PostHog needs reauthorization](#posthog-needs-reauthorization) | Tool result | The PostHog grant lapsed |
| [Database errors](#database-errors) | Tool result | The database refused the query |
| [Other tool errors](#other-tool-errors) | Tool result | A message that starts with the tool's name |

## Request IDs

Each response from an app's URL, except a 405, has a request ID in its `x-bonnard-request-id` header. An error from
the app's URL also gives it in the `request_id` field of the body:

```json
{
  "error": "audience_forbidden",
  "error_description": "This MCP server is not available to you. Ask the server owner to add you to its audience.",
  "request_id": "bnreq_<21 characters>"
}
```

Quote the `bnreq_` ID when you ask Bonnard for help. A script reads it from the header or the body. For a tool call,
the ID is in the HTTP header only. Sign-in pages show no request ID, so give the app, the AI client and the time
instead.

**Observability**, in the console at `app.bonnard.ai`, does not show the `bnreq_` ID. Its **Request id** field is a
different value: the AI client's own ID for the call.

## App URL errors

An app's URL answers an error with an HTTP status and, except for a 405, a JSON body: `error` (the code),
`error_description` (the message) and `request_id`. Each entry shows the `error_description`, or the whole body where
it differs. `<slug>` in a message is the app's name in its URL.

### `Method not allowed.`

```json
{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}
```

HTTP 405, with the header `Allow: POST` and no request ID. The app's URL takes POST requests only, so a browser that
opens the URL gets this answer. Install the app in an AI client with the URL instead. See
[Install in AI clients](https://bonnard.ai/docs/apps/install-in-ai-clients.md).

### `not_found`

> No MCP server for this endpoint.

HTTP 404. No app has this URL: the URL is wrong, or someone deleted the app. Copy the URL again from the app's
**Endpoints** card.

> MCP server '<slug>' is not live.

HTTP 404, on the production URL of an app that is not published. Select **Publish** in the app's header. See
[Publish the app](https://bonnard.ai/docs/apps/publish-and-staging.md#publish-the-app). The staging URL answers before you publish.

### `unauthorized`

```json
{"error":"unauthorized","request_id":"bnreq_<21 characters>"}
```

HTTP 401, with a `WWW-Authenticate` header that points to the app's sign-in details. The request has no
`Authorization: Bearer` header. An AI client reads the header and opens Bonnard's sign-in. A script sends its API key
in the header: `Authorization: Bearer <key>`. See
[Connect a script with an API key](https://bonnard.ai/docs/apps/install-in-ai-clients.md#connect-a-script-with-an-api-key).

### `invalid_token`

HTTP 401. The `error_description` gives the cause.

Table: invalid_token descriptions

| `error_description` | Cause and fix |
| --- | --- |
| `The access token has expired.` | An access token lasts 15 minutes. If the AI client cannot get a new one, sign in again from the AI client. |
| `The access token has an invalid issuer or audience.` | The token is for a different URL. The production and staging URLs have separate sign-ins, so sign in again with this URL. |
| `This access token has been revoked.` | On **Customers**, an admin selected **Sign out & revoke keys**, **Suspend access** or **Remove** for the user. After **Sign out & revoke keys**, the user signs in again. After the other two, an admin first restores the user's access. |
| `The access token signature could not be verified.` | Sign in again from the AI client. |
| `The access token is malformed or could not be verified.` | Sign in again from the AI client. |
| `The access token is missing the required subject or organization claim.` | The user's access changed after the sign-in. Sign in again from the AI client. |
| `The access token subject is not realm-typed.` | Sign in again from the AI client. |
| `The access token subject realm and customer context disagree.` | Sign in again from the AI client. |
| `The API key is invalid or has been revoked.` | The key is wrong or revoked, or its user has no access now. Create a new key. |
| `This API key is not valid for this MCP server.` | The key works for a different app only. Create a key for this app. |

### `forbidden`

> Staging is available to members of this workspace only.

HTTP 403, on a staging URL. Only members of the workspace that owns the app can use it. Your customers' users and
their API keys use the production URL.

### `server_misconfigured`

> The MCP server is misconfigured.

HTTP 500. Bonnard cannot load the app's settings. Quote the request ID when you ask Bonnard for help.

### `batch_too_large`

> This server accepts at most 100 JSON-RPC requests in one batch; this request carried <n>.

HTTP 400. A client sent more than 100 JSON-RPC requests in one batch, and Bonnard ran none of them. Send 100 or fewer
in each batch.

### `audience_forbidden`

> This MCP server is not available to you. Ask the server owner to add you to its audience.

HTTP 403, on the production and staging URLs. The person, or their customer, is not in the app's audience. Add them to
the app's [audience](https://bonnard.ai/docs/apps/audience.md). Each refusal is a denied call on
[Observability](https://bonnard.ai/docs/operate/observability.md).

### `no_test_context`

> Staging cannot tell which customer to serve this app as. Choose who staging tests as on the app's Overview tab.

HTTP 409, on the staging URL of an app on a database with tenancy. Staging acts as one customer. It selects that
customer by itself only when the app's audience has exactly one customer with a tenant. The app's **Overview** tab has
no control for this. See
[Which customer staging acts as](https://bonnard.ai/docs/apps/publish-and-staging.md#which-customer-staging-acts-as).

### `no_tenant`

> This server isolates data per tenant, so a personal (console) API key can't reach it. Use a tenant-bound customer key, or the staging "test as tenant" endpoint.

HTTP 403. The app's database has tenancy, and the caller has no tenant. The caller is one of these:

- A personal API key, from **Settings**, then **API keys**. Use a customer user's key instead: on **Customers**, select
  the customer, then **API keys** in the user's row menu.
- A user of a customer with no tenant. Set the customer's **Tenant binding** on **Customers**.

The message's staging suggestion does not work for an API key: on a staging URL, an API key acts as no customer.

### `not_serving`

> This app is not serving requests right now. Retrying will not help; an admin of the workspace that owns this app needs to act before it can serve again.

HTTP 402, for your customers' users and their API keys. The workspace that owns the app must act before the app
answers calls again. The AI client connects, but each request after that gets this error.

A user tells the company that gave them the app. An admin of that workspace finds the refused call on
[Observability](https://bonnard.ai/docs/operate/observability.md): its **Reason** names the cause.

### `payment_failed`

> Payment failed for this workspace and the grace period has ended. An owner needs to update the payment method before this app can serve calls again.

HTTP 402, for members of your workspace and their personal API keys. An Admin or Owner of your workspace updates the
payment method on the **Billing** page under **Settings**.

### `allowance_exhausted`

> This workspace has used all the calls included in its plan for this billing period. An owner needs to turn on extra usage or move to a larger plan before this app can serve more calls.

HTTP 402, for members of your workspace and their personal API keys. An Admin or Owner of your workspace selects
**Turn on extra usage** on the **Billing** page under **Settings**, or changes the plan.

### `no_payment_method`

> This workspace is past the calls included in its plan and has no payment method on file. An owner needs to add one before this app can serve more calls.

HTTP 402, for members of your workspace and their personal API keys. Extra usage is on, but no payment method is on
file. An Admin or Owner of your workspace selects **Add a payment method** on the **Billing** page under **Settings**.

### `spend_limit_reached`

> This workspace has reached the spend limit its owner set for this billing period. An owner needs to raise or remove that limit before this app can serve more calls.

HTTP 402, for members of your workspace and their personal API keys. An Admin or Owner of your workspace selects
**Edit spend limit** on the **Billing** page under **Settings**.

### `tenant_id_invalid`

> This customer's tenant id is longer than SQL Server allows (128 characters).

HTTP 403. On SQL Server with Multi-tenant (RLS), the customer's tenant has more than 128 characters. Give the customer
a shorter **Tenant binding** on **Customers**.

### `no_tenant_credential`

> This tenant has no data credential mapped on this server. Ask the server owner to map one.

HTTP 403. On BigQuery with a service account for each customer, this customer has none. Enter its service account in
the app's **Audience** card. See
[BigQuery with Dataset per tenant](https://bonnard.ai/docs/apps/audience.md#bigquery-with-dataset-per-tenant).

### `tenant_not_routable`

> This tenant is not mapped to a dataset on this server. Ask the server owner to map one.

HTTP 403. The customer's tenant has no dataset, database or schema on this app's database. On BigQuery with Dataset
per tenant, map the customer in the app's **Audience** card. On other engines, add the tenant to the database's
tenancy settings on the **Data** page.

## Sign-in errors

These errors show in the browser that the AI client opens for sign-in, or in the AI client after it.

### `access_denied`

Bonnard ends the sign-in and sends the AI client `error=access_denied` with one of these descriptions. The AI client
decides what to show.

Table: access_denied descriptions

| `error_description` | Cause and fix |
| --- | --- |
| `The user denied the request.` | The person selected **Deny**. Connect again from the AI client, then select **Authorize**. |
| `No eligible membership is available for this resource.` | The account is not a member of the workspace that owns the app, and not a user of a customer. Sign in with an account that can use the app. |
| `Choose which customer organization to connect.` | The account is a user of more than one customer, and the person selected none. Connect again, then select one under **Which organization?**. |
| `That customer membership is not available.` | The user's access to that customer ended during the sign-in. An admin restores it on **Customers**. Then connect again. |
| `That customer membership is no longer available.` | The same cause and fix. |
| `The customer membership bound to this authorization is no longer available.` | The user's access to the customer of an earlier sign-in ended. An admin restores it, or the user connects again and selects another customer. |
| `This authorization can no longer be completed.` | The customer's sign-in method, or the user's access, changed before the person authorised. Connect again from the AI client. |

### `rate_limited`

HTTP 429, with a `Retry-After` header: the number of seconds to wait. Bonnard counts sign-in requests for each IP
address, and password sign-ins for each email address and company domain. Wait for the `Retry-After` time, then try again.

Table: rate_limited bodies

| Body | Where |
| --- | --- |
| `{"error":"rate_limited","error_description":"Too many requests."}` | The sign-in requests that AI clients send: registration, authorization and token. Also the email step of the sign-in page. |
| `{"error":"rate_limited","message":"Too many attempts. Try again later."}` | Password sign-in, and new accounts, for one email address or company domain. |
| `{"message":"Too many requests. Please try again later."}` | Sign-in, email code and password reset requests from one IP address. |

Your customers' sign-in page shows `Too many attempts. Wait a minute and try again.` The numbers are on
[Limits](https://bonnard.ai/docs/reference/limits.md#sign-in) and [AI client access](https://bonnard.ai/docs/reference/limits.md#ai-client-access).

### Expired authorization request

> This authorization request has expired or is no longer valid. Please start the connection again from your AI client.

The browser shows this in place of the **Authorize access** page. The sign-in request is too old, or the page opened
again after the sign-in ended. The same page shows `Invalid authorization request.` when it opens with no
request, and `Could not load the authorization request.` when Bonnard cannot read it. In each case, start the
connection again from the AI client.

### `That code is invalid or expired.`

The sign-in page shows this after **Verify & connect**. The 6-digit email code is wrong, more than 10 minutes old, or
used up by 3 wrong entries. For a new code, select **Use a different email**, enter the address again, then select
**Send code**.

### No code arrives

After **Send code**, the sign-in page says `If that address can sign in, a 6-digit code will arrive shortly.` Bonnard
shows the same text when it sends no code. It sends none, for example, for an address that is not a user of a customer
with access to the app. It also sends none after too many code requests for one address. The person asks the company that gave
them the app to add their address. An admin of that workspace adds it as a user of the customer on **Customers**.

### `We could not continue this sign-in.`

The sign-in page shows the message with one of two endings.

Table: Endings of the message

| End of the message | Cause and fix |
| --- | --- |
| `Start the connection again from your AI client.` | After **Send code**: the sign-in request is not valid now. Start the connection again from the AI client. |
| `Try again.` | Bonnard cannot send the code, or cannot start single sign-on again. Select the button again. |

### Single sign-on fails

> We couldn’t sign you in
>
> Try again. If you still can’t sign in, contact your organization administrator.

The customer's identity provider did not sign the person in. Select **Try again**, or **Use a different email**. If the
sign-in fails again, the customer's IT admin examines the identity provider.

## Errors in tool results

A failed tool call returns text to the agent, marked as an error (`isError`), in place of a result. The messages are for the agent.
A person acts only where an entry says so. Each failed call is a record on
[Observability](https://bonnard.ai/docs/operate/observability.md), with the status `denied` or `error`.

### `invalid_arguments`

> <tool>: invalid arguments.
>
> Unrecognized argument "<name>"; did you mean "<name>"?

A JSON block follows with `"error": "invalid_arguments"`, the arguments at fault, and the `required` and `optional`
arguments. The agent sent arguments that the tool does not take. A person has nothing to do.

### Read-only refusals

> Empty query.
>
> Only a single statement is allowed.
>
> Only read-only SELECT queries are allowed.
>
> Write, DDL, or session statements are not allowed.
>
> Row-locking reads (FOR UPDATE/SHARE) are not allowed.

The agent gets one of these messages when its SQL is not one `SELECT` or `WITH` statement, or when it can write or lock
rows. On PostgreSQL and Amazon Redshift, Bonnard also refuses some functions, for example `pg_sleep` and `dblink`, with
`<function>() is not allowed.`

ClickHouse and MySQL / MariaDB add refusals of their own that end in `is not allowed.` or `are not allowed.`

The agent rewrites the query. Bonnard refuses these queries on each engine except Microsoft SQL Server, where the
login's grants decide.

### `Table '<name>' is not exposed.`

The agent asked `explore_schema` for a table that does not exist, or that the app hides. With the app setting
**Correct a wrong name** on (the default), the message adds the nearest table names and a hint. If the table must be
visible, show it on the app's **Data** tab. See [Table curation](https://bonnard.ai/docs/connect-data/table-curation.md).

### Database permission errors

> The database credential does not permit this operation.
>
> Ask the server owner to check the mapped credential and warehouse permissions.

On BigQuery, the first line is `The BigQuery credential does not permit this operation.` The result also names
`warehouse_credential_or_iam`. The database refused the query for lack of permission. Bonnard does not pass on the
database's own message, because it can name projects, tables or users.

Grant the read-only user, or the service account, access to what the agent queried. The connector page for your
database shows the grants, for example [PostgreSQL](https://bonnard.ai/docs/connect-data/postgresql.md#1-create-a-read-only-user).

### PostHog needs reauthorization

> This PostHog connection needs reauthorization. A workspace admin can reconnect it from the Data tab in the console.

The PostHog grant behind the connection lapsed. See [Needs reauthorization](https://bonnard.ai/docs/connect-data/posthog.md#needs-reauthorization).

### Database errors

When `sql_query` fails for another cause, the agent gets the database's own message, for example for a misspelt
column. One of these hints follows, the first for a column and the second for each other cause:

> Use explore_schema({ table: "..." }) on each table in your query to get its exact column names.
>
> Use explore_schema({ search: "..." }) to find the right table.

Query time and row limits are on [Limits](https://bonnard.ai/docs/reference/limits.md#queries).

The errors that your database sends when you connect it are on its connector page:
[PostgreSQL](https://bonnard.ai/docs/connect-data/postgresql.md#troubleshooting), [BigQuery](https://bonnard.ai/docs/connect-data/bigquery.md#troubleshooting),
[Amazon Redshift](https://bonnard.ai/docs/connect-data/redshift.md#troubleshooting),
[ClickHouse](https://bonnard.ai/docs/connect-data/clickhouse.md#troubleshooting),
[MotherDuck](https://bonnard.ai/docs/connect-data/duckdb-motherduck.md#troubleshooting),
[MySQL / MariaDB](https://bonnard.ai/docs/connect-data/mysql-mariadb.md#troubleshooting),
[Microsoft SQL Server](https://bonnard.ai/docs/connect-data/sql-server.md#troubleshooting) and
[PostHog](https://bonnard.ai/docs/connect-data/posthog.md#troubleshooting).

### Other tool errors

Other tool errors start with the tool's name, for example `explore_dashboards: unknown dashboard "<id>".` or
`render_chart failed: <message>`. The message names what to change in the call.
