إنتقل إلى المحتوى الرئيسي
This page is not available in العربية yet. You are reading the English version.

Troubleshooting

Find your symptom, then read its causes from the top. Each entry gives the exact text the browser or the API shows, so you can search this page for what is on your screen.

SymptomGo to
Nothing rendersNothing renders
The console reports a CORS error for …/sdk/sessionsCORS error on the session exchange
The console shows session exchange failed (403)Session exchange failed (403)
The chat panel is at the top-left of the browser windowThe panel floats at the top-left
Chat answers, but no pins appear on the mapNo pins appear
The map is 500 pixels tall, or has no heightThe map is 500px tall or has zero height
A published map says it is not allowed on this siteA published map is not allowed on this site
A request returns HTTP 429429 responses
A request returns HTTP 413, or 422 with a code such as conversation_too_long413 and 422: the request is too large
Chat stops answeringChat answers stop
A handle method or an attribute change does nothingA call or an attribute change does nothing

How Kaleidr reports a failure​

The SDK does not throw into your code for a failed mount, and has no error callback or ready event. The one call that throws is Kaleidr.mount with no options object, such as Kaleidr.mount('#map'): it raises a TypeError. A failure shows up in up to three places.

1. The console. Every SDK message contains [kaleidr. A failed mount logs one error in the form [kaleidr:<product>] <reason>, for example:

Error: [kaleidr:chat] kaleidr session exchange failed (403)

2. The Network tab. A keyed mount makes one request to https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions. Its status and its JSON body tell you why the server refused. The SDK shows only the status, as in the line above. The reason is in the response body. A 403 or 404 carries its code in a field named detail, as below. A 429 carries its code in a field named error, with a sentence in detail; the exception is map_load_quota_exceeded, which arrives in detail:

{ "detail": "insufficient_scope" }

3. Inside the frame, for Viewer. A published map that cannot load shows its reason as text where the map would be.

Reproduce the session exchange outside the browser​

When the browser hides a response behind a CORS error, make the same request with curl. Replace the origin with your page's origin, exactly as the browser sends it, and use your own key:

curl -i -X POST https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions \
-H "Origin: https://www.example.com" \
-H "Content-Type: application/json" \
-H "X-Api-Key: kld_pk_live_…" \
-d '{"product":"chat"}'

Use the product you are mounting: chat, tile or editor. A tile exchange that succeeds counts as one map load.

ResponseMeaning
200 with a session_tokenThe key, the origin and the product are all accepted. The problem is in the page, not the key.
401 {"detail":"Invalid or missing API key"}The key value is wrong, or the key is revoked or expired.
403 {"detail":"origin_not_allowed"}The origin is not in the key's allowed origins.
403 {"detail":"publishable_key_required"}The key is not a publishable key.
403 {"detail":"product_not_allowed"}The key is restricted to other products.
403 {"detail":"tier_capability_not_allowed"}The key carries what the product needs, but your current plan does not admit it.
403 {"detail":"insufficient_scope"}The key was created without the scope this product needs.
429See 429 responses.

Nothing renders​

Open the console and match the first Kaleidr line you see.

Console showsCauseFix
ReferenceError: Kaleidr is not definedYour script ran before the loader. This happens when the loader's script tag has async or defer, or comes after your script.Put the loader's script tag before your script and without async, or run your code after the loader's load event.
[kaleidr] <kaleidr-map> requires product="chat|viewer|editor|tile"The element's product attribute is missing or misspelled.Set product to one of the four values.
[kaleidr:<product>] mount target not found: #chatThe selector you passed to Kaleidr.mount matched nothing. Either it is wrong, or your script ran before the element existed.Fix the selector, or move the script below the element.
[kaleidr] embed is disabled — …The enable gate is holding the mount. The rest of the line names the control that holds it.Release that same control. See Consent.
[kaleidr:<product>] [kaleidr] failed to load https://cdn.kaleidr.com/embed/v1/<product>.jsThe product's script was blocked. Usually your Content Security Policy does not allow https://cdn.kaleidr.com in script-src; sometimes a browser extension or a network filter.Allow the host in script-src. Look for a Refused to load the script line just above.
[kaleidr:chat] chat.js loaded but window.KaleidrGeoChat is missing, or the same line for editor.js and window.KaleidrEditor, often after an Uncaught SyntaxError in that fileThe page declares no character encoding, and its copy of the loader is older than the 2026-10-13 release. The browser then read the product's script in the page's encoding instead of UTF-8, so the script did not run.Declare UTF-8 in the page's <head> with <meta charset="utf-8">, or use the current loader, which loads its scripts as UTF-8 whatever the page declares. A self-hosted copy has to be mirrored again to get it.
A CORS error for …/sdk/sessions, then [kaleidr:<product>] Failed to fetchThe key or the origin was refused.See CORS error on the session exchange.
[kaleidr:<product>] kaleidr session exchange failed (403)The key is accepted but may not mount this product.See Session exchange failed (403).
[kaleidr:<product>] kaleidr session exchange failed (429)A rate limit, or for Tile the map-load allowance.See 429 responses.
[kaleidr:<product>] Kaleidr: a server key (kld_sk_…) must never be used in the browser — it is a standing secret. Use your publishable key (kld_pk_…) here and keep the server key server-side.You passed a server key to the SDK. No request was made.Use a publishable key in the page. Because the server key was in page source, revoke it and create a new one.
[kaleidr:editor] [editor-embed] attach() requires an { apiKey }Editor was mounted without a key.Pass publishableKey.
[kaleidr:viewer] Kaleidr map: invalid id "" — must match ^[A-Za-z0-9._~-]{1,100}$.Viewer was mounted with no share-id, or with one that contains other characters.Pass the published map's id.
Refused to frame 'https://map-embed.kaleidr.com/'…Your Content Security Policy blocks the Viewer or Tile frame.Allow https://map-embed.kaleidr.com in frame-src.
Nothing from Kaleidr at allThe loader did not run, or nothing mounted.Check that the loader's script tag is on the page and returned 200, and that your Kaleidr.mount call or <kaleidr-map> element is actually reached.

Two cases where the product did render but you cannot see it:

  • A Viewer or a Tile below the fold has not loaded yet. Both frames load lazily, when they are scrolled near the visible area.
  • A chat panel with contained: true in a box with no height has no room to show. Give the mount target a height.

CORS error on the session exchange​

What you see. The console shows the browser's own CORS message, then the SDK's error. In Chrome:

Access to fetch at 'https://api.kaleidr.com/inference-api/b2b/v1/sdk/sessions' from origin
'https://www.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.

Error: [kaleidr:chat] Failed to fetch

Firefox and Safari word both lines differently (NetworkError when attempting to fetch resource., Load failed), but the pattern is the same: a CORS complaint about …/sdk/sessions, then a [kaleidr:<product>] error with no status code in it.

Why it looks like this. This is almost never a CORS configuration problem on your side. Kaleidr adds CORS headers to a response only when the key is valid and the calling origin is allowed for it. When either is not true, the API answers with a 401 or a 403 that has no CORS headers, and the browser refuses to show your page that response. The browser reports the missing header; the real refusal is behind it.

Causes and fixes.

CauseHow to confirmFix
Your page's origin is not in the key's allowed originsThe curl check returns 403 origin_not_allowedAdd the origin at kaleidr.com/api-keys: edit the key, add the origin to Allowed Origins. Match the scheme, host and port exactly.
The origin is listed, but not exactlyhttps://example.com is listed and the page is on https://www.example.com; or the port differsList each variant. There are no wildcards.
The key value is wrongThe curl check returns 401 Invalid or missing API keyCopy the key again. If you no longer have it, rotate the key to get a new value.
The key was revoked or has expiredSame 401; the key is missing from the API Keys page or not ActiveCreate a new key.
The page was opened from diskThe address bar starts with file://Serve the page over HTTP. See Quickstart.

The session exchange is the only request that behaves this way at mount. The preflight (OPTIONS) request before it always succeeds, so a 204 on the preflight does not mean the key was accepted.

Session exchange failed (403)​

What you see.

Error: [kaleidr:chat] kaleidr session exchange failed (403)

The key is valid and your origin is allowed, which is why the SDK could read the status. The server refused the product. Open the Network tab, select the sessions request and read detail in the response.

With a publishable key:

detailCauseFix
product_not_allowedThe key was created with a product restriction that does not include this product.Change the key's allowed products through the key API, or use a key without the restriction.
insufficient_scopeThe key was created without the scope this product needs: ai for Chat, maps for Tile, design for Editor.Scopes cannot be edited. Create a new key that carries the scope.
tier_capability_not_allowedThe key carries the scope, but your organization's current plan does not admit it.Check your plan under Billing.

With no key, on a published map (a Chat element with share-id), the request is to …/sdk/share-sessions:

Status and detailCauseFix
403 chat_disabledVisitor AI Chat is switched off for this map.The map's owner switches it on in Studio.
403 origin_not_allowedThe map is restricted to certain domains and this page is not on one of them.The owner adds the domain to the map's allowed domains.
403 owner_has_no_organization or tier_capability_not_allowedThe owner's account cannot provide chat.The owner checks their account and plan.
404 not_foundNo published map has this id.Check the share-id; publish the map.

After a refusal on a published map, the SDK does not ask again until the page is reloaded.

A key on a Viewer mount is unnecessary. Viewer needs no key; remove publishable-key from the element and the exchange is not made at all.

The panel floats at the top-left of the window​

What you see. The chat panel sits in the top-left corner of the browser window, over your navigation, and stays there when the page scrolls.

That is the default placement. Without contained, the panel is a fixed window positioned against the browser window, whatever element you mounted it on.

CauseFix
contained was not passedPass contained: true to Kaleidr.mount, or add the contained attribute to the element.
contained is set, but the mount target is not positionedGive the target position: relative (or absolute, fixed or sticky). The panel positions itself against the nearest positioned ancestor, and with none it uses the page.
contained is set, but the target has no heightGive the target a height. A <kaleidr-map> element is display:block by default; in Safari before 16.4 it stays inline, so also set display:block if you support that browser.
The panel is inside its box, but the box is below the map instead of over itThe chat element and the map element are siblings stacked one after the other. Put both in one positioned wrapper and lay the chat element over the map. See Chat on a published map.

A layout that works:

<div id="stage" style="position:relative; height:560px">
<div id="map" style="position:absolute; inset:0"></div>
</div>
<script>
Kaleidr.mount('#stage', { product: 'chat', publishableKey: 'kld_pk_live_…', map, contained: true });
</script>

To move the default floating panel away from the corner instead of docking it, see Theming and layout.

No pins appear​

What you see. The panel answers and names places, but no pins are drawn on your map. There is no console error. When Chat does not recognize the map it runs as a chat-only panel without saying so, and the camera does not move either. When only the library's page global is missing, the map is attached and the camera still flies to a single place.

CauseHow to confirmFix
The map library is not a page global. Chat finds the library at window.mapboxgl, window.maplibregl, window.L or google.maps. A library imported from npm does not set a global. Without it Chat cannot create pins or fit the view to several places, an area or a route.Type window.maplibregl (or your library's global) in the console. It prints undefined.Assign the global before you mount: window.maplibregl = maplibregl.
The map option is not the map instance. A CSS selector, the container element, or a framework wrapper around the map is not recognized.Check what you pass. For MapLibre and Mapbox the instance has getCanvas, getStyle and addControl methods.Pass the object your map library's constructor returned. With a framework binding, pass the underlying map instance, not the component reference.
map was undefined when you mounted, because the map is created laterLog the value on the line before Kaleidr.mount.Mount Chat after the map exists. The map is read once, at mount. To attach to a different map, call destroy() and mount again.
map-target matches nothingRun document.querySelector(yourSelector) in the console.Use a selector that matches the Viewer or Tile <kaleidr-map> element.
Both map and map-target were given—map-target is ignored when map is passed. Use one.
The answer contained no places with coordinatesAsk a plainly place-based question, such as "coffee near the Eiffel Tower".Nothing to fix. A place the assistant could not locate is listed in the conversation without a pin.
The library is not one Chat attaches toSee Supported maps.Use a supported library, or use a Tile element as the map.

The map is 500px tall or has zero height​

500 pixels tall, whatever height you set. For Viewer and Tile, the frame's height is decided once, at mount: it fills the element if the element has a height at that moment, and is 500 pixels otherwise.

CauseFix
The element has no height of its own. <kaleidr-map> is display:block by default, so a height on it applies, but it has to be set.Write style="display:block; height:480px", or size the element from your stylesheet.
The element is inline. Your own CSS sets display:inline (or another non-block value) on it, which overrides the default, or the browser is Safari before 16.4, where the element stays inline. On an inline element style="height:480px" alone has no effect.Write style="display:block; height:480px", or add a rule kaleidr-map { display: block; } to your stylesheet.
The height is a percentage and an ancestor has no heightGive every ancestor up to the sized one a height, or use a fixed or viewport height (480px, 60vh).
The element was hidden when it mounted, for example inside an inactive tab with display:noneMount the element when it becomes visible.

Zero height.

CauseFix
The element had a height when it mounted and lost it afterward. The frame is then 100% of nothing.Keep the element's height stable. Check for a parent whose height depends on its content.
It is your own map that has no height. Mapbox GL JS, MapLibre GL JS, Leaflet and Google Maps all need a container with a height, and Chat does not create one.Give your map's container a height.
A contained chat target has no heightGive the mount target a height.

A published map is not allowed on this site​

What you see. In place of the map, the frame shows:

This map isn't allowed to render on this site. Please contact the map owner.

The frame also posts a message to your window with type: 'kaleidr-embed:error' and code: 'domain_not_allowed'.

The map's owner has restricted it to a list of allowed domains, and the frame decides whether your page is on that list from the referrer the browser sends with the frame request.

CauseFix
The embedding page's domain is not in the map's allowed domainsThe owner adds the domain in Studio. A bare domain such as example.com also covers its subdomains.
The page sends no referrer. This happens with a Referrer-Policy: no-referrer header or meta tag on the page, or referrerpolicy="no-referrer" on the iframe. A domain-restricted map cannot verify such a page and refuses it.Use a referrer policy that sends at least the origin, such as the browser default strict-origin-when-cross-origin.
You are testing on localhostTest on a listed domain, or have the owner lift the restriction while you test.

The frame's other messages, and the code each one posts:

Text in the framecodeMeaning
This map isn't available — it may have been unpublished, paused, or the link is incorrect.not_foundNo live map has this id.
This map has reached its map load limit. It will be available again when the owner's allowance resets.map_loads_exhaustedThe owner's organization has used its map loads for the billing period.
Could not load the map. Please try again in a moment.fetch_failedA temporary failure loading the map.
Couldn't find a map id in the URL.no_idThe frame address has no id. With Tile, it means no style was given and your organization has no default: set style-id.
None. The map is shown, possibly with a part missing.maplibre_errorThe map started, but something on it failed to draw. It can arrive more than once, before or after the map is ready.

429 responses​

HTTP 429 means "not now". Kaleidr uses it for several different limits, and the response body says which. Read the body before you decide what to do.

BodyLimit reachedRetry-AfterWhat to do
{"error":"quota_exceeded", "meter":"b2b.tokens", "limit":…, "used":…, "remaining":…, "reset_at":"…", …} with a server key; {"error":"quota_exceeded", "meter":"b2b.tokens", "reset_at":"…", …} in a browser, where the plan and the numbers are left outYour organization's AI credits for the billing period, or the monthly limit set on this key. A request is refused when what remains cannot cover it.Seconds until the resetWait until the time in reset_at, buy an add-on pack, upgrade, or raise the key's limit. Retrying sooner will not help.
{"error":"rate_limited", "detail":"API key rate limit exceeded. Slow down."}The key's per-minute request budget, shared by every session of that key. Also returned when sessions are being requested too fast.A few secondsRetry after the delay. If it is frequent, split traffic across keys.
{"error":"visitor_limit_reached", "detail":"Chat limit reached for now. Try again later."}One visitor's limit on a published map's chatA few secondsNothing for you to fix. It protects the map owner's credits.
{"error":"org_overloaded", …} or {"error":"b2b_overloaded", …}Too many requests in progress at onceA few secondsRetry after the delay. Limit how many streams you run in parallel.
{"detail":"map_load_quota_exceeded"}Your organization's map loads for the billing period. Returned by the session exchange for Tile.NoneWait for the next billing period or buy a map-load add-on pack.
{"error":"tile_access_restricted", …} from tile.kaleidr.comMap tiles were requested directly instead of through a Kaleidr productOne hourShow the basemap with the Tile product.

How each shows up in the SDK:

  • A 429 on the session exchange fails the mount: [kaleidr:<product>] kaleidr session exchange failed (429).
  • A 429 on a chat question shows a line in the conversation: "You've reached your usage limit for now." The panel shows this line for every 429, with the reset time added when the body carries one. To tell a spent pool from a rate limit, read error in the response in the Network tab.

How each limit works, the plan allowances and how usage is counted are in Quota and rate limits. A key's own per-minute rate and monthly cap are the values set on that key.

413 and 422: the request is too large​

These come from your own code that calls the API. They mean the request was refused before any answer was produced, and nothing was charged. Retrying the same request returns the same refusal.

Status and bodyCauseFix
413 {"detail":"request_too_large"}The request body is larger than 2 MiB, or larger than 5 MiB on a /design/* endpoint.Send less. For chat, trim the conversation. For /design/analyze, send fewer sample rows.
422 {"detail":"conversation_too_long"}The messages of a chat request add up to more than 200,000 characters.Drop the oldest turns. See Reading the stream.
422 {"detail":"too_many_messages"}A chat request has more than 400 messages.Drop the oldest turns.
422 {"detail":"message_too_long"}One message is longer than 64,000 characters.Shorten the message.
422 {"detail":"invalid_session_id"}session_id is longer than 128 characters, or has a character other than a letter, a digit, _, ., : or -.Use a UUID.
422 {"detail":"lang_too_long"}lang is longer than 35 characters.Send a language tag such as fr or pt-BR.
422 {"detail":"field_too_long"}A field of a place-summary or place-question request is over its length limit.The limits are in Endpoints.
413 {"detail":"request_body_too_large"}A business-data upload request is larger than 32 MiB, or another account API request is larger than 1 MiB.See Upload your business data.
A refusal with no Kaleidr JSON bodyThe request declared a size far above any endpoint's limit and was refused at the network edge, before it reached the API.Send less. Do not expect a detail code on this response.

Chat answers stop​

Match what the panel shows.

Every question gets "Sorry — that didn't go through. Please try again."

CauseHow to confirmFix
Chat was mounted with neither a key nor a share-id. The panel renders, but its requests carry no credential.Your mount has no publishableKey and no shareId. The Network tab shows the stream request failing.Pass a publishable key, or a share-id for a published map with Visitor AI Chat on.
The key was revoked, or your origin was removed from its allowed origins, after the page loadedThe stream request fails with a CORS error; the curl check returns 401 or 403.Restore the origin or deploy a working key, then reload.
Your Content Security Policy blocks the APIThe console shows Refused to connect to 'https://api.kaleidr.com/…'.Allow https://api.kaleidr.com in connect-src.
Your organization's plan was downgraded while the page was openSessions issued before the change are refused with a 401, which the browser reports as a CORS error, until the SDK renews the session.Reload the page.
The visitor is offlineThe browser shows other network failures too.—

Questions get "You've reached your usage limit for now."

The request returned 429. See 429 responses.

An answer stops partway, and the failure line appears under the partial text.

The stream ended with an error. The text that arrived stays in the conversation. Ask again. If long answers fail regularly behind a proxy you control, check that the proxy does not buffer or time out long-lived responses.

Chat on a published map stops for everyone.

CauseFix
Visitor AI Chat was switched off for the map. Open pages stop within five minutes.The owner switches it back on.
The map was unpublishedThe owner publishes it again. The map keeps its id, so the page needs no change.
The map's monthly AI credit limit, or the owner's AI credit pool, is spentThe owner raises the limit, buys an add-on pack or waits for the next billing period.
The page's domain was removed from the map's allowed domainsThe owner adds it back.

Once a published map refuses a chat session, the page does not ask again until it is reloaded.

A call or an attribute change does nothing​

What you didWhat happensWhy
Called setCamera on a Chat handleConsole: [kaleidr] setCamera() is not supported on product "chat" — the call is a no-op. See the handle matrix at https://docs.kaleidr.com/sdk/kaleidr-map-element#handle-matrix.The assistant moves your map itself. To move it from your code, call your map library's own camera methods.
Called setTheme on a Viewer, Tile or Editor handle, or setStyle on anything but TileThe same warning, naming the method and the productEach product supports a subset of the handle. See the handle matrix.
Changed style-id, share-id or flag on a mounted elementNothingThese attributes are read once, at mount. Remove the element and add it again, or for a Tile's style call setStyle.
Set zoom without center on Viewer or TileThe zoom is ignoredAt mount, a zoom is applied only together with a center.
Passed a theme that is not an object or a JSON object stringConsole: a warning that begins [kaleidr] theme and ends ignored. or Ignored.Pass an object, or a JSON string of one.
Set base (the option, the attribute or window.__KALEIDR_EMBED_BASE__) to an origin that is not acceptedConsole: [kaleidr] base "https://other.example.net" is IGNORED — bundles load from https://cdn.kaleidr.com. A base must be the Kaleidr CDN, the origin kaleidr.js was loaded from, or this page's own origin. The product still mounts, with bundles from the default CDN. If your Content Security Policy does not allow that host, the bundle is then blocked and nothing renders.A base override is honored only for the Kaleidr CDN (https://cdn.kaleidr.com), the origin kaleidr.js was loaded from, or the page's own origin. Serve the loader and the bundles from the same origin. See CDN versioning.
Called setCamera or setStyle right after Kaleidr.mount on a Viewer or TileThe call is applied when the map is ready, not at onceCalls made before the map inside the frame is ready are kept and applied in order. If the map has not reported ready after a bounded wait, normally 10 seconds after the frame loads, the kept calls are sent anyway and the console shows [kaleidr] the map frame has not reported ready — calls held for it are sent now, and may reach no map. …. A frame that is showing an error has no map to apply them to: look for a kaleidr-embed:error message.
Set title on a chat elementA tooltip appears over the panel, and the header is unchangedtitle on an element is HTML's tooltip. The chat's header title is the chat-title attribute, or the title option of Kaleidr.mount.
Changed lang, chat-title or placeholder on a mounted chat elementNothingThey are read once, at mount. Remove the element and add it again.
The chat answers in English on a page in another languageThe page has no <html lang>, or its value is not a well-formed language tagPass lang to the mount, or set <html lang>. See Chat language.
Called a method on the handle and nothing happened, with a [kaleidr] embed is disabled warning earlierThe handle is inertThe enable gate held the mount. See Consent.

Still stuck​

Collect these before you ask for help; they answer the first questions anyone will ask:

  • The page's origin, exactly as shown in the address bar.
  • The first characters of the key, as shown on the API Keys page. Never send the full key.
  • The product you are mounting and the mount code or element.
  • The first console line that contains [kaleidr, and any CORS or Refused to… line near it.
  • The status and the response body of the sessions request, or of the request that failed.

Related pages: Errors for every code, Production checklist, and Content Security Policy.