Skip to main content

Errors

This is the complete list of errors from the Kaleidr platform API. Each has an HTTP status and a code: a short stable string you branch on. The status alone is not enough. 403 covers many different causes, and 429 covers both "slow down" and "you are out of quota".

Start with the shapes, because the code is not always in the same field.

Response shapes​

ShapeLooks likeUsed for
Wrapped code{"detail": "origin_not_allowed"}Almost every 401, 403, 404, 413, 500 and 503, the 422 request-limit codes, and two 429s (map_load_quota_exceeded, and ingest_rate_limited from the upload API). The code is the detail string.
Flat object{"error": "rate_limited", "detail": "API key rate limit exceeded. Slow down."}Every other 429. The code is error; detail is a sentence for a person. Quota errors add more fields.
Validation list{"detail": [{"loc": ["body", "product"], "msg": "…", "type": "…"}]}422 from a malformed body or query. detail is an array, one entry per problem.
Error at 200{"error": "Route planning failed."}POST /chat/control/route only. See below.

A function that reads the code from any of them:

async function kaleidrError(res) {
const body = await res.json().catch(() => ({}));
const code =
typeof body.error === 'string' ? body.error : // flat 429
typeof body.detail === 'string' ? body.detail : // wrapped code
Array.isArray(body.detail) ? 'validation_error' : // 422
'unknown_error';
return { status: res.status, code, body, retryAfter: Number(res.headers.get('retry-after')) || null };
}

Two headers matter: Retry-After on 429 responses, in seconds, and X-Request-Id when present, which identifies the request if you contact support.

Authentication: 401​

The API does not accept the credential.

CodeWhen it happensWhat to do
Invalid or missing API keyNo credential was sent, or the key is unknown, revoked or expired. Also: a session token that has expired; a session whose key was revoked or rotated without grace; a session whose origin or product was removed from its key; a session issued before a plan downgrade; an organization that is suspended or has no plan.Check the key and its status at kaleidr.com/api-keys. For a session, exchange a new one. If a valid key keeps failing, retry after a moment: a brief platform fault also answers this way.
publishable_requires_sessionA publishable key (kld_pk_…) was sent to a runtime endpoint.In a browser, let the SDK exchange it, or call POST /sdk/sessions first. On a backend, use a server key.

Authorization: 403​

The API knows the credential and refuses this request.

CodeWhen it happensWhat to do
insufficient_scopeThe key was created without the scope this endpoint or product needs.Use a key that has the scope. Scopes cannot be added to an existing key.
tier_capability_not_allowedThe key has the scope or product, but your organization's current plan does not include it. Also returned for a published map whose owner's plan does not include chat. Not returned for vendor: a key that carries vendor on a plan below Enterprise is not refused, and its answers are built without your data.Change plan, or use a product the plan includes.
server_key_in_browserA server key (kld_sk_…) was sent with an Origin header.Move the call to your backend. If the key was in page source, rotate it.
session_origin_mismatchA session token was used from an origin other than the one it was issued for, or a published-map session was used with no Origin.Exchange the session on the page that uses it.
ip_not_allowedA server or legacy key with an IP allowlist was called from an address outside it, or from an address that could not be established.Call from an allowed address, or change the key's allowed_ips.
publishable_key_requiredPOST /sdk/sessions was called with a server or legacy key.Use a publishable key for the exchange.
origin_requiredA session exchange had no Origin header.Make the exchange from a browser page.
origin_not_allowedThe page's origin is not in the key's allowed origins, or not in the published map's allowed domains.Add the exact origin to the key, or the domain to the map.
product_not_allowedThe key is limited to certain products and this request is for another one. At the session exchange: the requested product is not in the publishable key's allowed products. On a runtime endpoint: a server or legacy key called an endpoint of a product outside its allowed products, for example a key limited to tile calling /chat/*.Change the key's allowed_products, or use another key.
chat_disabledPublished-map exchange: the map's Kaleidr AI does not turn on the feature asked for.Turn on Control Tower or Popup Window in the map's Kaleidr AI tile in Studio.
feature_not_grantedA published-map session opened for popup chat was used on /chat/control/stream. Each feature has its own session.Exchange a session with "feature": "control_tower", which the map grants while Control Tower is on.
owner_has_no_organizationPublished-map exchange: the map's owner has no organization to charge.The owner must create or join an organization.

Not found: 404​

CodeWhen it happensWhat to do
not_foundPublished-map exchange: no published map or share link has this share_id.Check the id and that the map is published.
sessions_disabledSession exchange is switched off on the platform.Not something you can change. Contact support.
Not FoundThe path does not exist.Check the URL against Endpoints, including the /inference-api/b2b/v1 prefix.

Validation: 422​

The body or query string does not match what the endpoint accepts. detail is an array; each entry's loc names the field and msg says what is wrong.

{
"detail": [
{ "type": "missing", "loc": ["body", "product"], "msg": "Field required", "input": {} }
]
}

Fix the request; do not retry it unchanged. Two streaming endpoints, /chat/summary/stream and /chat/button/stream, answer a malformed body with 500 instead of 422, except for a field that is too long (below).

Request limits: 422 with a code​

A well-formed request that is over a size limit is also a 422, but with the wrapped shape: detail is the code as a string, not an array. Nothing is charged.

{ "detail": "conversation_too_long" }
CodeEndpointWhen it happensWhat to do
too_many_messages/chat/control/streammessages has more than 400 entries.Send the most recent turns only.
message_too_long/chat/control/streamOne message's content is longer than 64,000 characters.Shorten the message.
conversation_too_long/chat/control/streamThe content of all messages together is longer than 200,000 characters.Drop the oldest turns and send again.
invalid_session_id/chat/control/streamsession_id is longer than 128 characters or has a character other than a letter, a digit, _, ., : or -.Use an id in that form, such as a UUID.
lang_too_long/chat/control/streamlang is longer than 35 characters.Send a BCP 47 tag such as pt-BR.
field_too_long/chat/summary/stream, /chat/button/streamA text field is longer than its limit, or a list has more entries than its limit.Shorten the field. The limits are in Endpoints.

The limits for the chat stream are in Endpoints.

Request too large: 413​

CodeWhen it happensWhat to do
request_too_largeThe request body is larger than 2 MiB, or larger than 5 MiB on a /design/* endpoint. The body is {"detail": "request_too_large"}. Nothing is charged.Send less: trim the conversation, or the sample rows of a design request. Do not retry the same body.
request_body_too_largeA request to the key management or business-data routes under /shared-api is larger than 1 MiB, or larger than 32 MiB on the upload call POST /shared-api/datahub/ingests.Send a smaller body. For an upload, see Upload your business data.

A request that declares a size far above any endpoint's limit can be refused at the network edge, before it reaches the API. That response has no Kaleidr JSON body, so there is no code to read: send less.

A request refused for its size, like any request refused before it is processed, is not charged and holds no AI credits or concurrency slot afterward.

Quota and rate limits: 429​

Read the body before you decide whether to retry.

CodeFieldRetry-AfterWhen it happensWhat to do
quota_exceedederrorseconds to reset_atYour organization's AI credits cannot cover the call, or the key's own monthly cap would be exceeded. Also returned by the mapping-proposal call of the upload API.Do not retry. Wait until reset_at, add credits, or raise the key's cap.
rate_limitederror5The key's requests per minute are used up. Also: too many session exchanges for a key, a published map or one address.Wait Retry-After seconds, then retry with jitter.
org_overloadederror5Your organization has too many calls in progress at once.Wait for a call to finish, then retry. Close streams you no longer need.
b2b_overloadederror5The API is at capacity for all callers.Wait Retry-After seconds, then retry with backoff.
limiter_unavailableerror5The rate limiter could not answer.Retry shortly. This is not about your rate.
visitor_limit_reachederror5One visitor of a published map's chat has asked too much, per minute or per day.Tell the visitor to try again later.
map_load_quota_exceededdetailnonePOST /sdk/sessions for tile: the organization's map loads are used up.Do not retry. Wait for the period to reset or add a map-load pack.

The quota_exceeded body carries the numbers:

{
"error": "quota_exceeded",
"detail": "Usage limit reached. Please try again later.",
"product": "b2b",
"meter": "b2b.tokens",
"tier": "pro",
"limit": 5000000,
"used": 4999100,
"remaining": 900,
"reset_at": "2026-11-01T04:00:00+00:00",
"period": "month",
"reset_in_seconds": 1296000
}

That is the body a server key receives. A request made with a session token (a session exchanged from a publishable key, or a published map's visitor session) receives a shorter body that does not disclose the organization's plan or usage:

{
"error": "quota_exceeded",
"detail": "Usage limit reached. Please try again later.",
"meter": "b2b.tokens",
"reset_at": "2026-11-01T04:00:00+00:00",
"reset_in_seconds": 1296000
}

Each field, the per-key cap variant and worked handling code are in Quota and rate limits.

Server errors: 5xx​

StatusCodeWhen it happensWhat to do
500An internal error occurred. Please try again.An unexpected failure.Retry once after a short wait.
500map_design_analyze_failedPOST /design/analyze could not analyze the table. Not charged.Check the table's columns and sample rows; retry.
500Summary stream errorPOST /chat/summary/stream could not start: a body that cannot be read, or a building request with no address. A field that is too long is a 422 field_too_long instead.Fix the body.
500Button chat stream errorPOST /chat/button/stream could not start: a body that cannot be read or has no query. A field that is too long is a 422 field_too_long instead.Fix the body.
503sessions_not_configuredSession exchange is unavailable because of a platform fault.Retry; contact support if it persists.
503share_grant_unavailablePublished-map exchange: the map's settings could not be read.Retry shortly.

An error with status 200​

POST /chat/control/route returns 200 when a route cannot be planned:

{ "error": "Route planning failed." }

The response has error and no action. A client that checks only the status treats this as success and then fails reading action. Always check for error in the body. The text is written to be shown to a user. Details: Directions.

GET /retrieval/geocode/forward has a related behavior: a lookup that fails internally returns 200 with an empty results list, the same as a query with no matches.

Errors on a stream​

Everything above applies before a stream starts: a refused streaming request is an ordinary HTTP error. Once the response is 200 and frames are flowing, a failure arrives as an error event:

event: error
data: {"type": "error", "code": "upstream_stall", "message": "The AI service stopped responding. Please try again.", "partial_text": "The Louvre sits"}
StreamcodeWhen it happensWhat to do
/chat/control/streamupstream_stallThe answer stopped making progress, or the stream reached its maximum length of about 10 minutes.Offer a retry. Keep partial_text if it is useful.
/chat/control/streamabsentAny other failure while answering.Show message. A retry may succeed.
/chat/summary/streamabsentThe summary failed.Show message, or fall back to no summary.
/spot/overview/streamabsentThe overview failed, or the ref cannot be described. The event carries the ref when it cannot be described: a poi: or region: ref that is not at the point, place: without hint.name, or a building or an address, which the API does not describe.Show no overview. Do not retry an event that carries a ref.
/chat/button/streamnoneThis stream has no error event. A failure closes the connection without end.Treat a closed stream with no end as failed.

Rules for every stream:

  • An error event replaces end. Nothing but an optional quota event follows it.
  • A connection that closes with neither end nor error has failed.
  • The quota event is not an error. It is a usage report sent after end or error. On a stream read with a session token it carries only type, meter and reset_at.
  • An unknown event name is not an error. Ignore it.

A stream that fails or is closed part-way is still charged. On /chat/control/stream the charge is never less than an estimate of the conversation you sent, so it can be more than the hold placed at the start: see How a stream is charged. A retry is a new, separately charged request.

Errors a browser hides​

When the origin or credential is refused, the response has no CORS header, and the browser keeps the status and body from your code. The page sees a CORS error in the console and a rejected fetch; the SDK logs an error that contains [kaleidr:<product>].

To read the real code, open the Network tab and select the failed request. The common ones are origin_not_allowed, Invalid or missing API key and server_key_in_browser. See CORS and allowed origins.

A 4xx with no Kaleidr JSON body at all comes from the network edge, in front of the API. It is either rate limiting (back off and retry later) or a request whose declared size is far above any endpoint's limit (send less; retrying the same request gets the same answer).

Tile host​

Requests to tile.kaleidr.com that do not come from a Kaleidr embed with a valid publishable key on an allowed origin get:

StatusCodeRetry-AfterWhat to do
429tile_access_restricted (in error, with message and docs)3600Use the Tile product with a publishable key, and add the page's origin to the key if it has an allowed-origins list.

Key management​

Errors from https://api.kaleidr.com/shared-api/api-keys, which the API Keys page uses and which you can call with your account's access token. All use the wrapped shape.

StatusCodeWhen it happensWhat to do
401variesNo valid account access token. A platform key is not accepted here.Sign in again.
403org_admin_requiredYour account is not an owner or admin of the organization.Ask an owner or admin.
403plan_requiredThe organization has no plan.Choose a plan at kaleidr.com/billing.
403free_plan_publishable_onlyA server key was requested on the Free plan. Also returned when a server or legacy key is rotated on Free.Create a publishable key, or move to Pro.
403tier_capability_not_allowedCreating a key: scopes or allowed_products names something your plan does not admit. In practice this is a request for the vendor scope on Free or Pro; it is refused whether or not vendor_acknowledged is sent, and no key is created. Editing a key: allowed_products names a product the plan does not include, or, on Free, is set to an empty list.vendor needs Enterprise. Otherwise name scopes and products the plan admits.
404key_not_foundNo key with that id in this organization. Edit and revoke match a key in any status, so revoking a key that is already revoked returns 200. Rotate needs an active key, and returns this code for a revoked one.Check the id. For a rotate, the key may be revoked.
409key_limit_reachedThe organization holds its plan's limit of active keys (Free 2, Pro 10, Enterprise 25).Revoke a key, or rotate instead of creating.
409key_already_rotatedThe key has been rotated, whether or not its grace period has ended. It cannot be rotated again, and an edit that clears expires_at or sets it later than the end of the grace period is refused. An earlier expires_at and the key's other fields can still be edited.Use the replacement key.
409key_expiredA key that was never rotated has passed its expiry, and the edit includes expires_at. An expired key cannot be given a new expiry; its other fields can still be edited.Create a new key.
413request_body_too_largeThe request body is larger than 1 MiB.Send a smaller body.
422unknown_scopescopes contains a value other than ai, maps, design, vendor.Fix the list.
422unknown_productallowed_products contains a value other than chat, editor, viewer, tile.Fix the list.
422vendor_scope_requires_acknowledgementOn Enterprise, a publishable key with the vendor scope was requested without vendor_acknowledged: true. On Free and Pro the same request is a 403 tier_capability_not_allowed.Read the vendor scope, then send the field.
422no_fields_to_updateAn edit request with no editable field.Send at least one field.
422validation listA malformed origin, IP entry, expiry in the past, or name.Fix the field named in loc.
500insert_failed, session_unavailableA platform fault.Retry.
503api_key_pepper_not_configuredKey creation is unavailable because of a platform fault.Retry; contact support if it persists.

Business-data upload​

Errors from the upload routes under https://api.kaleidr.com/shared-api/datahub, and from the mapping-proposal call. The complete list, with the file and field limits behind each 422, is in Upload your business data. The ones that refuse a request before a file is read, and the ones from the calls that unpublish and delete a release:

StatusCodeWhen it happensWhat to do
403org_admin_requiredThe account is not an owner or admin of the organization. Also returned by the mapping-proposal call.Ask an owner or admin.
403vendor_data_not_on_planThe organization's plan may not upload business data. Uploading it is part of Enterprise only. Returned by the upload, publish, re-dispatch and mapping-proposal calls. Never returned by the calls that read, unpublish or delete.Move to Enterprise. GET /shared-api/datahub/limits reports whether an organization may upload, on every plan, without refusing. On Free and Pro, add data to a map in Kaleidr Studio instead: see Datasets on a map.
404release_not_foundUnpublish or delete: no release with that id in the organization, including one whose deletion has completed.For a delete, treat it as already done.
409org_ingest_in_progressAnother upload of the organization is being processed. Returned by the upload, publish and re-dispatch calls.Wait for it to finish, then send again.
409release_not_publishedUnpublish was called on a draft or failed release.Nothing to unpublish. Delete it instead.
409release_is_publishedDelete was called on the published release.Unpublish it, then delete it.
413request_body_too_largeThe upload request is larger than 32 MiB.Send a smaller file. The file itself may be up to your organization's size limit.
422{ "errors": [ … ] } in detailThe file is over a row or size limit, a field of a JSON bundle is over its length limit, or the JSON is nested too deeply. A reason for a limit set in your agreement names the limit and the plan.Read each reason and fix the file.
429ingest_rate_limitedThe organization started 30 uploads in the last hour.Wait, then send again.
429a sentence in detailThe account made 30 mapping proposals in the last hour. The body has no error field.Wait, then send again.
429quota_exceeded in errorMapping proposal: the organization's AI credits are used up. The body is the standard quota body.Wait until reset_at, add credits, or write the mapping by hand.

Dataset uploads in Kaleidr Studio​

This section is not part of the key-authenticated platform API. It describes what Kaleidr Studio receives when a signed-in user adds a dataset to a map in the Data panel and the upload is refused for its size. No API key is involved. There are two refusals, and they mean different things:

StatusCodeWhen it happensWhat to do
402quota_exceededA new dataset upload is over one of the organization's plan limits: the rows in one dataset, the size of one file, or the rows across all of the organization's datasets. The limit_key field says which. Data already stored is kept. Studio shows the message with a link to upgrade.Upload a smaller file, or remove datasets you no longer need. On Free, move to Pro. On Pro or Enterprise, contact Kaleidr for a higher total across the organization; the rows in one dataset and the size of one file cannot be raised past the ceilings in the next row.
400VALIDATION_ERRORThe file or the dataset is over a ceiling that applies on every plan: a file larger than 64 MiB, a dataset of more than 100,000 rows, a geographic file of more than 50,000 features, or an image overlay over 16 MiB. The code is in error. A plan change does not admit the upload.Split the file into smaller ones. Do not retry the same file, and do not offer an upgrade.

Which one you get depends on the size, not on the plan alone. The ceiling is checked first, so a file over 64 MiB or a dataset over 100,000 rows is a 400 on Free, Pro and Enterprise alike. The 402 is for an upload that is within the ceiling and over the organization's own limit: for example a 40 MiB file on Free, where the limit is 32 MiB.

402 quota_exceeded​

The body is a problem-details object that also carries Studio's own error and message fields. The code is in both error and code, and the sentence is in both message and detail:

{
"error": "quota_exceeded",
"message": "Your plan allows 250,000 rows across all of your organization's datasets. Delete a dataset or upgrade to add more.",
"type": "https://errors.kaleidr.com/datasets/quota_exceeded",
"title": "Quota Exceeded",
"status": 402,
"detail": "Your plan allows 250,000 rows across all of your organization's datasets. Delete a dataset or upgrade to add more.",
"code": "quota_exceeded",
"limit_key": "studio.data.rows.max",
"limit": 250000,
"used": 248500,
"tier": "free",
"upgrade_url": "https://kaleidr.com/pricing"
}
FieldMeaning
error, codeAlways quota_exceeded. The same value twice.
message, detailThe same sentence twice. It names the limit in plain words and is written to be shown to a person.
typeAlways https://errors.kaleidr.com/datasets/quota_exceeded.
titleAlways Quota Exceeded.
statusAlways 402.
limit_keyWhich limit refused the upload. See the next table.
limitThe organization's limit, in the unit of that limit.
usedFor the total, the rows the organization already holds. For the other two, the rows or the MiB of this upload.
tierThe organization's plan: free, pro or enterprise. It is unknown when the plan could not be read; the Free limits then apply.
upgrade_urlWhere to change the plan.
limit_keyLimitUnit of limit and usedThe sentence
studio.dataset.rows.maxRows in one datasetRows"Your plan allows 50,000 rows in one dataset. Upload a smaller file or upgrade."
studio.dataset.file.mbSize of one uploaded fileMiB"Your plan allows files up to 32 MB. Upload a smaller file or upgrade."
studio.data.rows.maxRows across all of the organization's datasetsRows"Your plan allows 250,000 rows across all of your organization's datasets. Delete a dataset or upgrade to add more."

The numbers in the sentences are the Free limits; the sentence you receive carries your organization's own. Show the sentence to a person and branch on code and limit_key. This 402 is a different response from the 429 quota_exceeded of the platform API, which is about AI credits.

400 VALIDATION_ERROR​

The body has two fields and no problem-details members:

{
"error": "VALIDATION_ERROR",
"message": "File is larger than 64 MB."
}
Refused formessage
A file over 64 MiB"File is larger than 64 MB."
A dataset of more than 100,000 rows"Maximum 100000 records per dataset"
A geographic file of more than 50,000 features"<filename> has more than 50000 features. Split it or simplify the geometry before uploading."
An image overlay over 16 MiB"Overlay image is larger than 16 MB."

The same status and code are returned for other problems with an uploaded file, such as a file type Studio does not read or a file with no usable rows; message says which. Treat every 400 from an upload as "this file cannot be added as it is", and show message.