Troubleshooting

On this page

RAGInitializationError on construction

Cause: one of vector_db, llm, chunker, context_manager was None.

Fix: the exception message lists exactly which arguments were missing — supply real objects for all four. See RAGSystem.__init__ Raises.

ValueError: ❌ Rerank weights must sum to 1.0 (got ...)

Cause: the four rerank_*_weight fields on RAGConfig, or RerankerConfig's equivalent fields, don't sum to within [0.99, 1.01].

Fix: adjust the weights so they total 1.0, or use the class defaults (0.40 / 0.40 / 0.10 / 0.10). See Configuration.

Reranker mode silently became "heuristic" even though I asked for "llm"

Cause: you constructed Reranker (directly, or indirectly via RAGSystem(config=RAGConfig(enable_reranking=True, rerank_mode="llm"))) without supplying an llm. Reranker.__init__ downgrades the mode automatically and logs a warning.

Fix: pass a working llm object. For RAGSystem, this is the same llm you already constructed it with — RAGSystem always passes self.llm into the Reranker it builds internally, so this specific scenario should only occur if you construct Reranker directly without an LLM. See Reranker constructor.

remove_document() returns 0 even though the document existed

Cause: RAGSystem.remove_document() catches all exceptions from vector_db.remove_by_doc_id() internally and returns 0 rather than propagating — so a 0 return can mean either "not found" or "an error occurred that was logged but swallowed".

Fix: check your application logs for an ERROR-level message from RAGSystem.remove_document to distinguish the two cases. See remove_document.

Async ingestion (aadd_documents) raises a TypeError I don't get from add_documents

Cause: add_documents() expects List[LoadedDocument]; aadd_documents() expects Dict[str, str] ({doc_id: text}). Passing the wrong shape to either will fail.

Fix: convert between the two shapes explicitly, or standardize on one ingestion path in your application. See the async ingestion warning.

Language detection thresholds differ across modules

Several independent language-detection implementations exist in the codebase, each with a slightly different heuristic:

LocationMethodThreshold
PromptRouter.detect_languageArabic-Unicode-block character ratio> 0.25 of non-space characters
RAGSystem._detect_language_simplePresence of any character in \u0600–\u06FFAny single character
query_expansion._detect_languageArabic-Unicode-block character ratio> 0.30
evaluation.RAGEvaluator._detect_langPresence of any character in \u0600–\u06FFAny single character

Symptom: the same input string might be classified as Arabic by one code path and English by another (e.g. a short English sentence containing one Arabic word will be "ar" under the "any character" methods but likely "en" under the ratio-based methods).

Fix: if consistent language classification across the pipeline matters for your use case, detect the language once yourself (pick one method) and pass it explicitly wherever a language parameter is accepted (RAGSystem.generate(..., language=...), PromptRouter.build(..., language=...)), rather than relying on each module's independent auto-detection.

DocumentVersionManager.add_or_update() raises ImportError

Cause: the method internally imports LoadedDocument from zerda.rag.core.rag_system, which only resolves if core is installed within that package namespace. See Architecture.

Fix: install/vendor core as zerda/rag/core/ rather than as a bare top-level core package, or patch the import if you maintain a fork.

rollback() raises ValueError

Cause: original_texts (the dict you pass to rollback()) doesn't contain an entry for the doc_id you're rolling back.

Fix: DocumentVersionManager does not retain full historical text (only hashes and short previews) — you must supply the original text yourself. See rollback.

My retrieval cache never seems to help (hit_rate stays near 0)

Likely causes, in order of likelihood based on the source:

  1. High query diversity relative to cache_maxsize — increase cache_maxsize.
  2. Frequent document ingestion clearing the cache — see Cookbook: avoiding cache-clearing storms.
  3. Using the async path — aretrieve() never touches the cache at all, by design; only the synchronous retrieve() does. See aretrieve.

Related pages