Debugging Playbook
High-level mental model
Searchlite is a single-index, single-writer system with:
- •buffered writes (CLI or HTTP)
- •durability via WAL + atomic manifest updates
- •immutable segments + periodic compaction
- •“refresh” semantics for making new commits visible to readers (especially in HTTP mode)
Most “weirdness” is one of:
- •you didn’t commit (writes are buffered)
- •you didn’t refresh (reader is stale)
- •your schema isn’t configured for what you’re asking (e.g., missing
fastfields for filters/aggs) - •you’re seeing crash-window replay artifacts (extra segments until compaction)
- •you’re hitting HTTP limits (body size, concurrency, timeouts)
10-minute triage checklist
- •
Identify surface area
- •CLI? embedded Rust API? HTTP server?
- •
Capture exact versions + features
- •git SHA/tag (if known)
- •build flags / enabled features (
vectorschanges behavior materially)
- •
Get a minimal reproduction
- •schema JSON
- •the smallest NDJSON/JSON doc set that reproduces
- •the exact search request JSON or CLI flags
- •
Check index state
- •CLI:
searchlite inspect <index>andsearchlite compact <index> - •HTTP:
GET /inspect,GET /stats, optionallyPOST /compact
- •CLI:
- •
Confirm lifecycle steps
- •Writes are queued → must call
commit - •Depending on config, may need
refreshfor immediate visibility
- •Writes are queued → must call
CLI debugging moves
A) “I added docs but search returns nothing”
Common causes:
- •Documents missing the required ID field (
doc_id_field, default_id) - •You didn’t run
commit - •Query is hitting an analyzer mismatch or field mismatch
Checklist:
- •Verify you ran:
- •
searchlite add … - •
searchlite commit …
- •
- •Run:
- •
searchlite inspect <index> - •
searchlite search <index> --q "..." --return-stored(or request JSON withreturn_stored: true)
- •
- •If segments ballooned after a crash, run:
- •
searchlite compact <index>
- •
B) “Filters/aggs don’t work / always empty”
Filters and aggregations depend on fast fields.
- •Ensure the target keyword/numeric fields are
"fast": truein schema. - •For nested filters, ensure nested subfields are
fasttoo and useNestedfilters properly.
HTTP debugging moves
A) Safety + environment sanity
HTTP server has no auth / no rate limiting; don’t expose it to untrusted networks. When debugging production-ish behavior, always capture:
- •bind addr (
--bind/SEARCHLITE_BIND_ADDR) - •index path (
--index/SEARCHLITE_INDEX_PATH) - •resource limits:
- •
--max-body-bytes - •
--max-concurrency - •
--request-timeout-secs - •shutdown grace
- •
- •refresh behavior:
- •
--refresh-on-commit
- •
B) Confirm lifecycle and visibility
Writes issued via:
- •
POST /add(NDJSON streaming) - •
POST /bulk(JSON bulk) - •
POST /delete
…are queued and only become durable/searchable after:
- •
POST /commit
Then visibility depends on staleness needs:
- •if
--refresh-on-commitis enabled, new data becomes visible immediately - •otherwise call:
- •
POST /refresh
- •
C) Use maintenance endpoints for ground truth
- •
POST /refresh— reload readers - •
POST /compact— merge segments + clean up fragmentation - •
GET /inspect— manifest + segments info - •
GET /stats— doc/segment counts
D) Interpret HTTP errors
All errors return:
- •
{"error":{"type":"...","reason":"..."}}
If you see a 413/timeout-ish behavior:
- •check
--max-body-bytesand--request-timeout-secs - •for NDJSON streaming, reduce batch sizes / request size
Ranking correctness + “why did this score happen?”
Search supports explicit debugging aids:
explain: true
- •Returns per-hit score breakdowns.
- •Use this for correctness (“why did doc X win?”), not for performance runs.
profile: true
- •Adds execution stats like:
- •candidates examined
- •scored docs
- •postings advances
- •timing buckets (search vs rescore)
- •Use this for performance triage (“why is this query slow?”).
Both are off by default for overhead reasons.
“This query is slow” playbook
- •Enable
profile: trueon the request and capture the profile blob. - •Compare execution modes:
- •
execution=bm25(baseline full scoring) - •
execution=wand(default exact pruning) - •
execution=bmw(block-max pruning)
- •
- •Confirm you’re not forcing expensive features:
- •rescore windows
- •heavy highlighting
- •large aggregations on high-cardinality fields
- •If using aggregations:
- •confirm required fields are
fast - •consider sampling knobs where supported
- •confirm required fields are
- •If using vector search (feature
vectors):- •remember ANN is approximate; raising
candidate_size/ef_searchincreases recall but costs CPU
- •remember ANN is approximate; raising
Vector search “it errors / results look wrong”
Common causes:
- •wrong vector dimension (rejected)
- •using cosine without normalization assumptions (Searchlite normalizes cosine vectors automatically)
- •expecting exact results from ANN (HNSW is approximate)
Knobs to tune:
- •
candidate_size(oversampling) - •
ef_search(beam width) - •
vector_filter(reduce candidate set)
Nested filter “it matches too much / too little”
Key rule: nested filters are evaluated per object, not across the entire document.
Correct pattern:
- •wrap clauses under
Nestedwithpath - •for deeper nesting, use a nested
Nestedinside the parent nested filter
Common gotcha:
- •forgetting to mark nested filter fields as
fast: true
Storage/durability anomalies
Symptoms:
- •“extra segments” after crash
- •“duplicate generation” feeling after restart
Remember the documented crash window:
- •if the process dies after manifest persisted but before WAL truncation, WAL replay reapplies last batch
- •data isn’t lost, but you may see extra segment generations until compaction
Fix:
- •run
compact(CLI or HTTP) to merge and clean up
What to attach to a bug report
- •schema JSON
- •small docs ndjson/json
- •exact request JSON (include
execution,profile,explainif relevant) - •output of
inspect+stats - •server flags/env (HTTP)
- •if durability related: note whether crash/restart occurred