Errors

How Telmoni reports errors on the API and in the console: problem documents (RFC 9457), error types, status codes, and the two the machine host's door mints.

Telmoni reports API and console errors using Problem Details for HTTP APIs (RFC 9457, sent as application/problem+json). Each problem document carries a stable URI type your code can branch on.

The shape of an error

{
  "type": "/errors/authz/insufficient-role",
  "title": "insufficient role",
  "status": 403,
  "detail": "required admin, have member"
}
  • type is a URI that identifies the problem kind. It never changes between deployments.
  • title is a short, human-readable summary of the problem type.
  • status is the HTTP status code, repeated inside the body.
  • detail is human-readable and explains this specific occurrence. Some errors carry none, so treat it as optional.
  • Additional keys may appear on specific error types, as noted below.

Error types

TypeStatusMeansExtra fields
/errors/auth/unauthenticated401You are not signed in, your session was ended, or your account is being deleted; on the CLI's lanes, also a request that carried no credential.
/errors/auth/token-expired401Your session has expired. Sign in again.
/errors/auth/invalid-token401The credential sent is not valid, or the API got none.
/errors/auth/service-credential-rejected401One of Telmoni's services refused another's credential. This is Telmoni's fault, not yours. Only the console's own calls to the server meet it: the API, the CLI's lanes and ingest take no service credential.
/errors/auth/identity-unavailable503Telmoni could not check who you are right now, because the identity provider's keys or its own identity service could not be reached. Try again shortly.
/errors/auth/not-found404The thing you named does not exist, or is not yours to see. detail says what kind of thing.
/errors/auth/bad-request400A value was not acceptable, such as a malformed email address. detail says which.
/errors/auth/bad-url400The URL asked for an organization is not one it may go by: not lowercase letters and digits in words joined by single hyphens, longer than 48 characters, a word the console's own pages use, or a word no URL may hold. detail says which, without repeating a word no URL may hold. A URL another organization holds is a 409 instead.
/errors/auth/conflict409It already exists, conflicts with something that does, or something is not in the state the request needs, such as deleting your account while you own an organization other people are in. detail says what.
/errors/auth/sso-required403Your address's domain signs in through the deployment's identity provider alone, so the email-and-password form refuses it: sign-in, sign-up and a password reset. The sign-in page offers the provider's button instead (Configuration).
/errors/auth/sign-up-closed403A new person was turned away because the deployment lets new people in by invitation (AUTH_DISABLE_SIGNUP, on by default), at the email-and-password form or through its identity provider. An address an invitation is waiting for still gets in. After a provider's sign-in, the console shows a page saying so.
/errors/authz/forbidden403You are signed in and this is not allowed. detail says why.
/errors/authz/insufficient-role403Your role does not allow this. detail names the least role that would, such as required admin, have member.
/errors/tenant/cross-tenant-denied403Reserved for a request that reaches outside the organization or project it may act in; no lane returns it.
/errors/bad-request400The request body or query string is not the shape the lane takes, or a value failed its rule. detail names the shape or the parameter, never the value sent.
/errors/payload-too-large413The request body is larger than this route accepts, such as a body over 8 KiB sent to the CLI's lanes.
/errors/not-found404No lane answers at this path on the machine host, under /v1, /cli or /otlp. Not a resource a lane looked for: that is /errors/auth/not-found. Under /otlp the body is OTLP's Status rather than a problem document, its message opening with the type.
/errors/method-not-allowed405The lane does not take this method. The Allow header lists the ones it does. On /otlp/v1/traces the body is OTLP's Status.
/errors/incompatible-client426Reserved for a client older than the oldest version Telmoni supports; no lane checks a client's version, so none returns it.
/errors/tenant/rate-limited429Too many requests. Wait and try again. A Retry-After header carries the same number of seconds. On the hosted service the same type answers the ceiling of the organization's plan on its data out for the UTC day — the read API's answers and the exports — until midnight UTC; detail says so.retry_after_secs
/errors/tenant/feature-off503This feature is switched off, for your organization or for the whole deployment. detail says which in a sentence.flag, retry_after_secs
/errors/mail/delivery-failed502An email this request depended on, such as a confirmation code, could not be sent.
/errors/connectors/key-unavailable502The key that seals connector secrets could not be reached, so a connector could not be set up or its secret rotated. Nothing was changed; try again shortly.
/errors/internal/database500Telmoni's database failed.
/errors/internal/unknown500Something else on Telmoni's side failed.
/errors/agent/disabled503The operator of this deployment has not configured the console agent.
/errors/agent/model-unavailable502The model or embeddings service behind the console agent did not answer. Nothing was changed; try again shortly.
/errors/agent/rate-limited429You have asked the console agent as many questions as this hour allows.retry_after_secs
/errors/telemetry/invalid-batch400An export to /otlp/v1/traces did not decode as OTLP in the encoding its Content-Type named, held no span, held more than 1,000, did not arrive within 60 seconds, or could not be read. On that lane the body is OTLP's Status rather than a problem document, its message opening with the type.
/errors/telemetry/batch-too-large413An export was larger than 1 MiB once decompressed. Send fewer spans per export.max_bytes
/errors/telemetry/store-unavailable503The store that keeps spans, or the key service that seals a project's hashing key, did not answer; or a project's first export came while the project was being moved to another organization or deleted. Nothing was kept; retry after the second Retry-After gives.retry_after_secs
/errors/plan/limit-reached402What was asked is past what the organization's plan holds. Only a deployment that sells plans answers it, never a self-hosted one: on the hosted service, a paused organization's exports, agent questions, invitations and members added to a project from it, an invitation past Hobby's one member and the seat it would take, a second organization asked for while the person's Hobby place is held, which is paid for first instead, a cancellation of an organization that could not fall to Hobby, and an organization offered to someone whose free plan is already taken (Billing). detail says what lifts it; on /otlp/v1/traces it is OTLP's Status, its message opening with the type, and an exporter drops the export rather than retrying it.entitlement

feature-off answers 503 with a retry hint, not 404, on purpose: the route exists and the switch is Telmoni's, so a program should wait and retry rather than conclude the route is gone.

Methods, and lanes that do not exist

Every lane under /v1 and /cli answers a problem document, the two the door itself mints among them; ingest, under /otlp, answers OTLP's Status instead, these two among them (Sending spans).

A method a lane does not take is 405 with an Allow header, /errors/method-not-allowed. The API takes GET and HEAD, and OPTIONS alone answers 204 with Allow: GET, HEAD, OPTIONS; the CLI's lanes and ingest take POST, and every other method, OPTIONS included, is told so:

{
  "type": "/errors/method-not-allowed",
  "title": "method not allowed",
  "status": 405,
  "detail": "this lane takes POST"
}

A path no lane serves, under /v1, /cli or /otlp, is 404 with /errors/not-found: a type apart from /errors/auth/not-found, which a lane answers about a resource it looked for and did not find, so a client can tell a missing lane from a missing row:

{
  "type": "/errors/not-found",
  "title": "not found",
  "status": 404,
  "detail": "no such lane"
}

On /v1, a server that cannot reach its database while it checks the key answers 503 with /errors/auth/identity-unavailable, from the table; anywhere else a database failure is 500 with /errors/internal/database.