Skip to content

Copilot LLM errors

The Building OS Copilot talks to whichever LLM a building has connected in Building Settings → AI Assistant. Every failure on that path — a bad key, a throttled account, an unreachable self-hosted endpoint — is mapped to one of the stable codes below before it reaches the UI or the API. Users never see a raw provider response or a 500; they see the code's title and detail, plus a Learn more link to the section on this page.

How errors reach you

  • In Building OS the Copilot panel renders the error card. The Recent calls panel in Building Settings → AI Assistant keeps the last calls per building with their provider, model, latency and error code.
  • Over the API a failed chat request answers with the code's HTTP status and this body:
json
{
  "code": "RATE_LIMITED",
  "title": "Rate limited",
  "detail": "The provider is throttling your requests. Wait a moment and try again, or upgrade your plan.",
  "helpUrl": "https://developers.tango.vision/reference/llm-errors#rate-limited"
}

code is stable and safe to branch on. title and detail are copy and may change. When the provider returns a JSON error body, detail carries the provider's own message so you do not have to open its console.

  • Test connection (in the add-LLM wizard, or POST …/llm-configs/:id/test) answers { ok: false, errorCode, message } with the same codes.
CodeHTTP status
INVALID_API_KEY401
MODEL_NOT_FOUND404
RATE_LIMITED429
PROVIDER_UNREACHABLE502
PROVIDER_TIMEOUT504
PROVIDER_INTERNAL_ERROR502
UNSUPPORTED_FEATURE422
BAD_REQUEST400
NOT_CONFIGURED424
ENCRYPTION_UNAVAILABLE503
UNKNOWN500

Invalid API key

INVALID_API_KEY — the provider answered 401 or 403.

  • Re-paste the key in Building Settings → AI Assistant. Keys are stored encrypted and never shown again, so a typo is invisible until the first call.
  • Check the key belongs to the account and region of the base URL you entered. A key from one provider's EU console does not work against its US endpoint.
  • Self-hosted endpoints (custom endpoints) that require no key still receive a placeholder bearer token; if your gateway rejects unknown tokens, configure it to accept the placeholder or issue a real key.
  • Providers that authenticate with a header other than Authorization: Bearer (Azure OpenAI's api-key, for example) need that header set via extraHeaders when the config is created over the API.

Model not available

MODEL_NOT_FOUND — the provider answered 404.

  • The model name is misspelled, retired, or not enabled for this account or tier. Pick one from the provider's model list.
  • A wrong base URL also produces a 404. The platform appends /chat/completions to the base URL, so https://host/v1 is right and https://host or https://host/v1/chat/completions is not. Fix the base URL before changing the model.

Rate limited

RATE_LIMITED — the provider answered 429.

  • Wait and retry; most limits are per minute.
  • Raise the account's quota or tier, or move the building to a key with its own quota. Several buildings sharing one key share one limit.

Provider unreachable

PROVIDER_UNREACHABLE — the platform could not open a connection at all (DNS lookup failed, connection refused or reset).

  • Check the base URL host for typos.
  • The request leaves from the platform's API server, not from your browser. A self-hosted model that answers on your laptop or inside a private network must be reachable from the cluster that runs tv-api. localhost in a base URL refers to the API server, not to your machine.
  • Check the provider's status page and your outbound network rules.

Provider too slow

PROVIDER_TIMEOUT — no complete answer within the platform's limit (60 s per chat call, 10 s for the connection test), or the provider answered 408 or 504.

  • Try a smaller or faster model, or a region closer to the cluster.
  • Self-hosted models loading into memory on the first request often time out once and succeed afterwards; run Test connection twice before digging in.

Provider error

PROVIDER_INTERNAL_ERROR — the provider answered 5xx (other than 504).

  • Usually transient; retry in a moment.
  • If it persists, check the provider's status page. Nothing on the platform side changes this outcome.

Feature not supported

UNSUPPORTED_FEATURE — the provider or model lacks something the Copilot needs.

  • The Copilot drives the building through tool calls (OpenAI-style function calling). Choose a model that supports it; many small self-hosted models do not.
  • The native Anthropic, Gemini and GigaChat providers do not implement streaming yet. The Copilot uses non-streaming calls, so this only affects integrations that request streaming explicitly.

Invalid request

BAD_REQUEST — the provider rejected the request with another 4xx.

  • detail carries the provider's own message when it sent one.
  • Typical causes: a parameter the model does not accept (temperature, max tokens), a request larger than the model's context window, or a gateway that expects a different request dialect. The call is listed in the Recent calls panel.

AI Assistant not configured

NOT_CONFIGURED — no LLM is connected to this building, and the platform has no fallback configured.

  • Open Building Settings → AI Assistant and add a provider. The building's default config is the one the Copilot uses; a saved but non-default config is not enough.
  • Platform operators can set an environment-level fallback (LLM_PROVIDER, LLM_API_KEY, LLM_BASE_URL, LLM_MODEL on tv-api) that applies to every building without its own config.

LLM bridge offline

ENCRYPTION_UNAVAILABLE — the platform could not decrypt the stored API key.

  • The API server's LLM_CONFIG_ENCRYPTION_KEY is missing, or it changed after this config was saved. Keys encrypted with the old value cannot be read.
  • A building admin can recover by re-entering the API key in Building Settings → AI Assistant, which re-encrypts it with the current platform key. Ask your platform administrator if it keeps happening.

Unexpected error

UNKNOWN — a failure none of the mappings above recognised.

  • The detail is recorded with the call in the Recent calls panel and in the API server's logs.
  • Report it with the building id and the time of the call; every UNKNOWN that is reproducible becomes a named code.

Adding a code

Codes live in LlmErrorCode in tv-api (src/copilot/providers/), and each provider maps its wire-level failures to one of them. A new code needs, in the same change: the union member, its entry in ERROR_CATALOG with a helpUrl pointing at this page, and a section on this page whose anchor is the code in lower-kebab-case (PROVIDER_TIMEOUT#provider-timeout). The catalog's tests check the URL shape; this page is what the link has to land on.

Built on the Tango Vision platform. Questions? developers@tango.vision