Troubleshooting
Indexed by symptom, because several different causes produce the same one. Most of the entries below share a shape worth knowing up front: a query Indx refuses comes back looking like a query that simply found nothing.
The first check, for any "no results"
A refused search returns 200 with no records and a populated reason (Reason in C#). An honest
no-match returns 200 with no records and reason: null. They differ in that one field and
nowhere else.
const result = await search(client, query);
if (result.reason || result.didTimeOut) {
// Refused or timed out — a failure. Say so; never render it as "no results".
}Do this once, in whatever wraps your search calls, and most of this page stops being able to bite you. Then read on for the cause.
Search returns nothing, for every query
A fieldBoosts key that is not a searchable field empties the whole search. Unknown fields and
fields that were searchable until someone changed the configuration both do it. The response
says so: reason carries "FieldBoosts contains unknown or non-searchable field" with the field's
name, so the first check above catches it.
Check the boost keys against the configuration:
curl -H "Authorization: Bearer $KEY" \
".../api/teams/$TEAM/datasets/$DATASET/fields/configuration"Every key you send must appear there with "searchable": true. The tell is a surface split: the
page that sends boosts returns nothing while a page that sends none works perfectly. If you keep
weights and boosts in code, assert one against the other in a test — see
the field configuration how-to.
The dataset is not Ready. GET status reports the state and, when it failed, errorMessage.
A dataset that is loading, indexing or hibernated cannot serve.
An empty query returns nothing
Empty text needs enableFacets: true. Without it the query is refused rather than treated as
match-everything, with reason set to Search called with empty string and EnableFacets=false. The
dataset also needs at least one facetable field. See Empty search.
Inserts fail with "field(s) not in the field configuration"
The document carries a field the dataset does not know, a new field in your CMS, say. Insert
and update refuse it with 400 invalidArgument naming the field, and store nothing: one such
document fails its whole batch. (Until October 2026 the field was accepted, shown in hit payloads
and never indexed, so "the field shows in results but searching on it finds nothing" is the same
cause on an older server.)
Only Replace can add a field. Re-analyze and rebuild from a full export
(POST …/replace, or Options → Replace data in the console), which reports the fields it added.
Configuring roles and weights on existing fields does not need it.
The mirror image is worth knowing too: a field in your configuration that the engine has not
discovered is rejected, taking the whole configuration call down with a
400 invalidArgument. One optional field that happens to be empty in every document is enough. Apply
what the engine discovered and report the rest loudly, rather than sending a configuration the
dataset cannot accept.
The result count is wrong, or suspiciously round
A count equal to coverageDepth is the cap, not your data. Coverage confirms only the first
coverageDepth candidates (default 500), so a broad query reports exactly that many. Raise it to
the document count; the cost is linear in depth, so on small and mid-sized datasets it is effectively
free. See Deep coverage.
The list and the facet counts disagree. They ran at different depths, so they describe different universes. Use one depth per surface.
Results are ranked oddly after a change
fieldBoosts multiply the configured weight, they do not replace it. A field at weight: 3.0
with a boost of 3.0 counts 9×. Keep the ladder in the field configuration and use boosts only for
what one surface wants differently.
Pattern matching always returns its nearest shapes, so a loose query can never answer "nothing" —
and score does not separate a useful guess from noise. Search precisely first
(coverageSetup.includePatternMatches: false); only if that finds nothing, search again with pattern
matches on, and label those rows as guesses. See Exact hits and
Pattern only.
A request that used to work returns 404 or 403
403 insufficientKeyScope — the key's access level is below what the endpoint needs. Search only
keys search; reads like export and field configuration need Read only; writes need Full access.
404 — the team or dataset is outside the key's scope. This is deliberately the same answer as a
team or dataset that does not exist, so names cannot be enumerated through a key. Two causes look
identical here:
- the key names datasets and this is not one of them;
- the dataset was renamed. A key that lists datasets by name silently stops reaching a renamed one.
- the team was renamed. The team name is part of every path (
/api/teams/{team}/…), so calls to the old name find no team. The keys themselves keep working; update the path. - the key is a personal key and its owner left the team. A personal key acts as the person who made it. For anything deployed, use a team key (Manage team → API keys), which does not depend on one person's membership.
Keys cannot be edited after creation. To change a level or a dataset list, create a new key and revoke the old one.
Search works locally but not in production
The key belongs to the other server. Keys are signed per server, so a key minted on your local
instance fails against the cloud with 401 and a signature error, and the reverse. Check the host
the key was created on before anything else.
A VITE_-style build-time variable changed without a redeploy. Anything inlined at build time
ships with the bundle; changing it in the hosting dashboard does nothing until the next deploy.
A term stays empty long after the index recovered
An empty answer was cached. A query that ran during a reload or against a not-ready dataset
returns no records; cache that and the term stays empty for the life of the entry. Cache hits, not
misses, and never cache a response carrying a reason or didTimeOut.
Nothing here matches
GET status is the first place to look: it carries the state, the document count, and
errorMessage from the last refused call. Errors from the HTTP API are RFC 9457 problem documents
with a machine-readable code — see the HTTP endpoints reference for the full table.