Troubleshooting and FAQ
This is the FAQ hub for semanticastindexer (SAI). Each entry pairs a symptom you’ll
see (an error message, an empty result, a missing tool) with the cause and the
fix. Most problems fall into one of three buckets: a first-run model download, a
dimension/feature mismatch, or an MCP wiring issue.
For deeper background see Backends and embedders, Environment variables, and MCP clients.
Q: The first run hangs for a long time, or fails with no network. What is it doing?
On the local DuckDB path with the ort (ONNX Runtime) embedder, the very first run
downloads the model and tokenizer from Hugging Face: onnx/model.onnx and
tokenizer.json from the repo named by duckdb.model_repo. That download happens once;
later runs reuse the cache.
- Where the cache lives: the standard Hugging Face Hub cache at
~/.cache/huggingface. Each repo lands under~/.cache/huggingface/hub/models--<owner>--<name>/. - Slow download: the ONNX model is the big file (hundreds of MB for code models). Progress is printed; let it finish — it is cached afterward.
- No / restricted network: if you already have a populated cache, point the embedder at it instead of the default location and run offline.
# sai-cfg.yml — reuse a pre-populated HF cache (no network on subsequent runs)
duckdb:
model_cache: /path/to/huggingface/cache
duckdb.model_cache sets the Hugging Face cache directory the ort embedder reads from
(it maps to the Hub client’s cache dir). To force fully offline behavior regardless of the
cache location, export HF_HUB_OFFLINE:
export HF_HUB_OFFLINE=1
With HF_HUB_OFFLINE=1, the Hub client never reaches the network and uses only what’s
already cached — so the model and tokenizer must already be present, or the run errors.
If you pre-stage the cache once and then run normally, you do not need
HF_HUB_OFFLINE at all; the cache hit is automatic.
If the model download itself fails you’ll see:
failed to download onnx/model.onnx from <repo> (check network or set duckdb.model_cache to a pre-populated dir)
Q: The first run fails on tokenizer.json with “relative URL without a base”. What’s wrong?
You are running a build older than the hf-hub 0.5 upgrade. The old pinned hf-hub 0.3
client could not fetch files that Hugging Face stores in Xet storage — for the
recommended code model jinaai/jina-embeddings-v2-base-code, onnx/model.onnx downloaded
fine but tokenizer.json errored with relative URL without a base.
Fix: upgrade to a current build; the first-run download of both files now works.
If you must stay on an old build, stage tokenizer.json into the model’s HF cache
snapshot once with curl, then run normally:
# Old builds only: stage tokenizer.json into the cached snapshot for the jina code model
SNAP=~/.cache/huggingface/hub/models--jinaai--jina-embeddings-v2-base-code/snapshots/*/
curl -sL https://huggingface.co/jinaai/jina-embeddings-v2-base-code/resolve/main/tokenizer.json -o $SNAP/tokenizer.json
See Choosing a model and Backends and embedders for the full model recommendation.
Q: I get “embedder produced N-d vectors but vector_dim=M”. How do I fix it?
The DuckDB table’s embedding column is declared FLOAT[vector_dim], so the embedder’s
output dimension MUST equal the configured vector_dim. A mismatch means the model and
vector_dim disagree, or you switched models without rebuilding the index. The runtime
guard prints the right dimensions for the common models:
embedder produced 768-d vectors but vector_dim=384 — set vector_dim to match the model (e5-small=384, nomic-embed-text=768, mxbai-embed-large=1024)
When you open an existing index whose stored column type no longer matches, you get the column-level variant instead:
DuckDB table '<collection>' has embedding column of type FLOAT[384] but config/vector_dim=768 (expected FLOAT[768]). This usually means the embedding model was changed without --recreate. Delete the DuckDB file or re-index with --recreate.
Fixes (any one):
-
Set
vector_dimto match your model —e5-small= 384,nomic-embed-text= 768,mxbai-embed-large= 1024,jinaai/jina-embeddings-v2-base-code= 768. -
Re-index with
--recreate(drops and recreates the collection):./target/release/semanticastindexer --backend duckdb --recreate --root src --ext rs -
Delete the DuckDB file (and its
.walsidecar) and re-index:rm -f .index/code.duckdb .index/code.duckdb.wal
The interactive delete prompt. On a normal index run (not --query-only), if SAI
opens an index that has a dimension mismatch, it offers to delete and rebuild for you:
The index at '<path>' was built with a different embedding model (dimension mismatch). Delete it and re-index from scratch? [y/N]
This prompt defaults to No and only deletes on an explicit y/yes. When stdin is
not an interactive terminal (CI, git hooks, the MCP stdio server), it auto-declines
and the original error propagates — automation never blocks on input and never destroys an
index by default. A --query-only run never re-indexes, so it just surfaces the error
rather than offering to delete (deleting would only leave an empty DB to query).
Q: I get “Document API only works on Qdrant Cloud”. Why?
The qdrant backend uses Qdrant’s server-side inference (the Document API) — there is
no local model on this path; the cluster embeds your text. Plain OSS/local Qdrant has
no inference engine, so the Document API only works against Qdrant Cloud (or another
inference-enabled deployment) with Inference enabled and the embedding model available
on the cluster.
Fixes:
-
Use a Qdrant Cloud cluster with Inference enabled and the embedding model present (
intfloat/multilingual-e5-small, vector size 384, context window 512). Provide the API key in the environment (the URL can beqdrant.urlin YAML orQDRANT_URL):export QDRANT_URL="https://<cluster-id>.<region>.aws.cloud.qdrant.io:6334" # gRPC :6334 export QDRANT_API_KEY="<key from the cluster's API Keys tab>" -
Or switch to the fully local DuckDB backend, which embeds on-device and needs no cluster:
./target/release/semanticastindexer --backend duckdb --root src --ext rs
See Qdrant Cloud setup and the Environment reference.
Q: I get a “rebuild with –features …” error. What does that mean?
Backends and embedders are compiled behind Cargo feature flags. Selecting a backend or embedder whose feature was not built into the binary fails with a clear “rebuild with –features …” message. Likewise, if no embedder feature is compiled in, the embedder errors with:
no embedder compiled in (build with --features ort or --features ollama)
Fix: rebuild with the feature you need. The simplest catch-all enables everything:
cargo build --release --features all
Or enable just what you use, for example the local DuckDB + ONNX + AST path:
cargo build --release --features "duckdb,ort,ast"
The ast chunker is also feature-gated — selecting chunker: ast (or auto-selecting it)
without the ast feature errors early. See
Backends and embedders for the feature matrix.
Q: I get zero results, or duplicates/similar misses obvious matches. Why?
A few independent causes:
-
The index is empty. Run an index first. With the DuckDB MCP server, a missing index is an explicit error:
DuckDB index not found at <path> — run an index first (the MCP server is read-only). -
Recall degraded after deletes (DuckDB only). DuckDB’s experimental HNSW index loses recall after in-place deletes. SAI’s
synctherefore wraps its changed-file loop in a bulk window (begin_bulk/end_bulk) that drops and recreates the HNSW graph, restoring full recall — effectively a full rebuild of the graph. If rows were deleted by some other means, run async(or re-index) so the graph is rebuilt:./target/release/semanticastindexer sync --backend duckdb -
Threshold too high for your model. Code-trained models score lower than E5, so a
duplicate_min_scoretuned for E5 can hide real near-duplicates. Lower the threshold for the jina code model (e.g.0.88). See Tuning similarity. -
Wrong prefix style for the model. Both embedders apply E5’s
passage:/query:prefixes by default; a symmetric or non-E5 model wantsprefix_style: none, otherwise relevance suffers.
Q: My MCP client doesn’t show the sai_* tools. How do I wire it up?
A handful of wiring issues account for almost every “the server doesn’t appear” report:
- Use an absolute command path. Point the client at the built binary by absolute path,
e.g.
/abs/path/to/target/release/semanticastindexer, not a bare name your client may not resolve. - Set the working directory to the indexed project. The server resolves the index and
config relative to its cwd, so the client must launch it with
cwd= the project you indexed (where.index/code.duckdb/sai-cfg.ymllive). - Restart the client. Most MCP clients only read server config at startup; after editing the config, fully restart the client so it spawns the server again.
- The server is read-only by default. It runs with
--backend duckdb --embedder ollamadefaults and is read-only; thesai_refreshwrite tool is not registered unless you start it with--allow-write. Without that flag,sai_refreshreturns a clear “restart with –allow-write” error. Thesai_prepare_mcp_setuptool only executes the setup script when started with--allow-setup. - Index first. A read-only server cannot index; if
.index/code.duckdbdoes not exist yet, run an index before launching the server.
Minimal stdio launch (read-only) and the writable variant:
# read-only MCP server over stdio (defaults: duckdb + ollama)
/abs/path/to/target/release/semanticastindexer mcp
# writable: also registers the sai_refresh tool
/abs/path/to/target/release/semanticastindexer mcp --allow-write
The full list of sai_* tools and their argument schemas lives in the
MCP server reference; per-client config snippets are in
MCP clients.
Q: The MCP server can’t load the DuckDB VSS extension. What now?
The DuckDB backend needs the VSS extension (for HNSW search and array_cosine_distance).
SAI tries a plain LOAD vss first (works on read-only connections if VSS was previously
installed), then INSTALL vss; LOAD vss, then the community repo. If all fail you get an
actionable error. The common fix is to install VSS once with a writable run:
- Run the indexer at least once with write access so it can
INSTALL vss, or - Pre-install for a read-only MCP server:
duckdb -c "INSTALL vss;"as a user who can write to DuckDB’s extension directory, or - In an air-gapped environment, copy the VSS extension into DuckDB’s extension search path before starting the read-only server.
See Performance and Security for related operational
notes, and Keeping in sync for the sync workflow that
keeps recall healthy after edits.