Troubleshooting#
This page covers common problems with a chat embedded through the Neo SDK, and the error codes that the proxy returns. The error code is the error field in the JSON body of the response, which the network panel of the browser shows. For setting up the proxy and the page, see the Embedding Neo Chat in Your Own App or Site page.
The Chat on Your Page#
Answers Arrive All at Once Instead of Streaming#
A reverse proxy between the browser and the chat proxy buffers the response. For nginx, set proxy_buffering off; and a generous proxy_read_timeout on the location of the chat. Some CDNs need buffering turned off for that path as well.
The Chat Is Invisible#
<neo-chat> has no height. Give it display: block and a height. A floating chat needs no size.
Dialogs Are Cut Off at the Edge of a Container#
In the React setup, an ancestor of NeoSdkProvider with a transform, filter, contain, or clipping overflow limits the dialogs of the chat to its own box. Move the provider outside that ancestor.
CORS Errors in the Browser Console#
The page and the proxy are on different origins, and the origin of the page is missing from corsOrigins. Add the origin of the page to ALLOWED_ORIGINS, which the templates use for both corsOrigins and the anonymous origin check.
Signed-In Readers Get 401 across Origins#
The proxy relies on a session cookie, which does not reach a proxy on another origin. Switch the page to auth: 'token' with a getToken function, or serve the proxy from the origin of your page.
The Recent Files List Is Empty#
This is expected. Because every reader shares the service account, the proxy refuses to list files, and it refuses uploads too, unless it sets allowUploads: true.
Math Symbols Render as Plain Letters#
Math in answers uses the serif font of your page instead of the KaTeX math fonts. Blackboard, calligraphic, and fraktur letters then render as plain ones, and stretchy delimiters keep text-size parentheses. If your answers need them, load katex.min.css from KaTeX, fonts included, in your own page.
A Document with a Reserved ID Does Not Open#
The widgets and sdk.items refuse an item ID that matches a name that the Squirro API reserves, before any request is sent. <neo-item-detail> reports it as a neo-item-detail-error. For the reserved names, see the docs/chat.md file in the package.
The PDF Viewer#
The PDF Viewer Never Finishes Loading#
The viewer files come from your proxy at <baseUrl>/assets/nutrient/. Check the network panel of the browser for assets/nutrient/ requests:
If the page and the proxy are on different origins, and the origin of the page is missing from
corsOrigins, the browser blocks the downloads of the viewer. The viewer never reports that, so the SDK waits 30 seconds, and then shows an error that names the assets URL and CORS.If the route responds with
404, because the proxy hasserveNutrientAssets: falseor@nutrient-sdk/vieweris missing from its installation, the error names the viewer script instead.A Content Security Policy without
worker-src blob:or'wasm-unsafe-eval'stops the viewer as well, and the console names the directive.
The reader can still open the file from Open original in the document header.
A Blocked Request to nutrient-powered.io in the Console#
The PDF viewer reports usage to Nutrient after loading, at least when it runs without a license key. Your Content Security Policy or your network blocked that report. The viewer is not affected.
Proxy Startup#
The Proxy Exits at Startup, or Answers 503 proxy_not_ready#
The startup check failed, and the error names why:
Assistant memory is on
Memory is on for the service account in the project that the error names. Turn it off, or set
ALLOW_SHARED_MEMORY=1if every reader may share one memory.Scheduled tasks not allowed
ALLOW_SHARED_AGENT_TOOLSmust listtasks, because a project cannot turn off scheduled tasks. Set it totasks,filesystem, or totasksif file storage is turned off in every project that the proxy serves.File storage not turned off
ALLOW_SHARED_AGENT_TOOLSdoes not listfilesystem, and the error namescapability.filesystem.enabled. Pin it tofalsein the project manifest and in every agent that sets it, or addfilesystemif every reader may share the file storage of the service account.The refresh token was refused
The error says that exchanging
refreshTokenfailed. Your Squirro instance refusedSQUIRRO_REFRESH_TOKENbecause it is mistyped, expired, revoked, or replaced by a renewed token, because the role of the service account changed, or becauseSQUIRRO_API_URLpoints at the wrong place.It could not check
The proxy could not read whether memory is on, or the catalog of the project. If the error names a
403, the service account is not a member of that project, or the ID inPROJECT_IDis wrong. Otherwise, your Squirro instance did not respond, or responded with an error. The proxy does not serve requests until the check succeeds.
For how to turn off memory, and how to share or turn off file storage, see the Prepare the Service Account and the Project section of the Set Up the Proxy page.
A proxy whose check failed responds with 503 proxy_not_ready, and the first request 10 seconds later runs the check again. A proxy that keeps running therefore recovers once your Squirro instance responds or the setting is fixed. When the check fails at startup, the templates exit instead, and rely on the process manager that restarts them. An error that says “the proxy has stopped serving” comes from the check that the proxy repeats while it serves: memory or file storage was turned on while the proxy ran, without being allowed.
Requests Refused or Failing#
403 origin_not_allowed or origin_required#
The origin of the page is not in ALLOWED_ORIGINS, or the browser sent no origin at all. Check the exact scheme, host, and port. A page served with Referrer-Policy: no-referrer sends no origin on same-origin requests. Relax the policy on pages with the chat, or use bearerSession.
403 cross_site_request#
A request that changes something came from a page whose origin the proxy does not recognize as its own. Usually, a reverse proxy in front sends a different Host than the browser used. The nginx default is Host: $proxy_host, with no X-Forwarded-Host. Add proxy_set_header Host $host;, or list the origin of the page in ALLOWED_ORIGINS with the templates, or in trustedOrigins otherwise. Alternatively, send X-Forwarded-Host and set trustProxy: true on createChatProxy, which the templates do not set. TRUST_PROXY is a different setting, for the rate limit. A page on another site is refused on purpose.
403 host_not_allowed#
The Host of the request is not in the allowedHosts of the proxy. Add the host name that the browser uses.
403 agent_not_allowed#
The reader picked an assistant outside allowedAgentIds. If readers may use it, add its ID to allowedAgentIds.
403 uploads_disabled or 400 file_ids_not_allowed#
Uploads are off, because every reader shares the service account. Set allowUploads: true on the proxy only if every reader may see the files of every other reader.
400 query_value_not_allowed or 403 purge_not_allowed#
A request carried a query parameter value that the SDK never sends. The proxy forwards only the parameters that the requests of the SDK carry. A 403 purge_not_allowed appears only when your own isAllowedPath opens conversation deletion, and a request asks for a hard delete while every reader shares the service account.
404 for a Project That Exists#
The project is not in PROJECT_ID. Add its ID to PROJECT_ID.
404 for Every Document#
With the Workspaces feature turned on, the proxy needs the tenant of the workspace that holds the project, and SQUIRRO_TENANT is not set. The proxy reports it once to onWarning. Set SQUIRRO_TENANT. For which tenant to set, see the Which Tenant to Set section of the Set Up the Proxy page.
413 payload_too_large#
A request body other than an upload is over 1 MB. The chat never sends one that large, so check what sends the request.
The Express Proxy Serves Nothing#
The handler is mounted under a path, for example with app.use('/api/chat', ...). Express then strips that prefix from the request URL, and the handler finds nothing to serve. Mount the handler without a path, as the proxy-express.mjs template does.
Rate Limits#
The limits in this section apply to the anonymous(...) mode of the proxy.
429 rate_limited#
The address of the reader used up its rate limit, or its stricter budget for questions and searches, expensiveRateLimit, 20 per minute by default. The Retry-After header of the response says when to try again. If many readers share one address, for example behind a corporate gateway, raise max. If your proxy sits behind a load balancer, set trustProxyHeader: true in anonymous(...), or TRUST_PROXY with the templates, so that each reader is counted separately.
The files of the PDF viewer and artifact downloads count against a separate budget, assetRateLimit, 600 requests per minute by default. Raise it for readers behind one gateway who open many PDF documents.
Every Reader Hits 429 at the Same Time#
The proxy counts every reader as the same address. Usually, it sits behind a reverse proxy that does not set X-Forwarded-For, or that the proxy does not trust. Add proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;, and check TRUST_PROXY. For a reverse proxy on the same machine, the onWarning of the proxy says which of the two it is, once. For a reverse proxy on another host, nothing warns, so set TRUST_PROXY explicitly.
429 too_many_streams#
One address already has four expensive requests in flight, such as answers streaming, uploads, or searches (maxConcurrentStreams). Readers behind one gateway share the limit, so raise it for those deployments.
429 too_many_requests#
One address already has 16 requests in flight (maxConcurrentRequests), such as documents that it opened and has not finished reading. Readers behind one gateway share the limit, so raise it for those deployments.
429 too_many_downloads#
One address already has four documents or artifact downloads in flight (maxConcurrentDownloads), such as PDF documents that it opened and has not finished reading. Readers behind one gateway share the limit, so raise it for those deployments.
Downloads#
Download Does Nothing: 403 invalid_signature or signature_expired#
Download in the chat fetches the signed link of the artifact, and saves the response. When the proxy refuses it, nothing is saved, and the chat reports it through callbacks.onNotify, which the SDK forwards to onWarning by default, so it shows in the console. The 403 and its error show on the request in the network panel of the browser.
signature_expiredmeans that the download link has expired. Click Download again for a fresh link.invalid_signaturefor every download usually means that thetenantoption of the proxy names a tenant other than the one that holds the project. For which tenant to set, see the Which Tenant to Set section of the Set Up the Proxy page.
Download Does Nothing: 429 rate_limited#
As with the 403 in the previous section, nothing is saved, and the 429 shows in the network panel of the browser. With bearerSession or your own authorize, signed artifact downloads have a budget of their own, signedDownloadRateLimit, of 30 per minute for each conversation by default. A reader who downloads more than that from one conversation in a minute waits for Retry-After.
If you set key: 'client' in signedDownloadRateLimit, the budget applies to each reader address instead. Behind a reverse proxy, also set trustedHops to the number of reverse proxies in front, or every reader counts as the address of the reverse proxy and they all share one budget. trustProxy does not help here, because it only changes the cross-site check.