When RAG Misses the Document You Know Is There
Recall failures that survive every smoke test, and how to prove the document was never a candidate.
A missing-document failure is a recall miss at the candidate set: the document you can open on disk never appears among the chunks passed to the model. It is not the case where a chunk came back and was the wrong one (see wrong chunk), and it is not the case where retrieval was fine but the model still answered badly: that is generation-side (lost in the middle, hallucination, conflicting sources). Barnett et al. (2024) catalogue the retrieval half of this split as Missing Content versus Missed the Top Ranked Documents in their seven failure points (arXiv 2401.05856). Label Studio’s March 2025 guide retells the same pair as Failure 1 and Failure 2. Before you rewrite prompts or swap models, prove the document was never a candidate. Smoke tests that only check whether the bot answered miss this failure entirely. The RAG failures hub places it under index and retrieve; the job here is to show which gate kept the document out.
How do you prove the document was never a candidate?
A missing document is proven by ordered checks that rule causes in or out, not by changing every knob at once. Run these on one query whose answer you can point to in a known source file. Each step either finds the document or eliminates a cause; stop when the cause is named. Label Studio’s Failure 1 and Failure 2 write-ups (March 2025) and Barnett et al. (2024) name the end states (content absent versus ranked too low) without shipping this rule-in, rule-out order, so the sequence below is the diagnostic spine.
The five checks share one constraint: you already know which file should answer the query. Without a gold document ID or path, you cannot tell absence from the candidate set apart from a generation failure that still received some other passage. Non-Brand Data’s 23-pitfall list (pitfall 2) makes the same point from the corpus side: a RAG system can only retrieve indexed content, so gaps look like model errors until you inspect the store.
Run the checks in this order so cheap confirmations come first and expensive ranking experiments come last:
- Look up the document ID (or source path) directly in the index. If the ID is absent, retrieval never had a chance: fix ingest first.
- Re-run with every metadata filter removed. If the gold document appears only then, a filter was excluding it.
- Raise top-k well above production (for example to 50). If the gold appears at a rank greater than your production k, the cutoff, not absence from the corpus, was the gate.
- Compare BM25-only to dense-only on the same query. If sparse finds the gold and dense does not, vocabulary, not “the model”, is the gap.
- Grep the source for the answer string and check it against chunk boundaries. If the answer straddles a split so no single chunk matches the query, granularity kept the document out of the candidate set.
If a chunk is returned and it is simply the wrong passage, you have left the missing-document case: that is a confidently wrong retrieval. If you need the full stage-by-stage procedure after recall is known to be low, use how to find which stage broke. Once absence from the candidate set is proven, the next question is which of the five gates produced it.
Which of the five causes kept it out?
Five causes produce the same symptom (the document never reaches the model) and each has a different fix. Pipeline walkthroughs try every stage in order. Faster is differential diagnosis: one measurement per row that rules that cause in or out before you change code. Non-Brand Data’s retrieval pitfalls (over-reliance on a single method, too few documents, ignoring metadata) name several of these gates as separate list items; the differential that follows binds each gate to a single discriminating delta.
Read the table left to right. The detection column is what you run first; the fix column is what you change only after that measurement fires. Competitors such as Label Studio’s seven-failure guide and Chirag’s hierarchical dual-index write-up (Medium, captured September 2026) describe remedies without this rule-in measurement, so teams still guess which knob to turn.
| Cause | What you see | Detection (run this first) | Fix |
|---|---|---|---|
| 1 · Never indexed | File on disk; no row for its ID in the vector store | index.contains(doc_id) = false | Re-ingest and verify the ID is searchable |
| 2 · Filter excludes it | Indexed and embedded; invisible until filters drop | recall(no-filter) – recall(with-filter) | Metadata filtering |
| 3 · Vocabulary mismatch | Query words differ from document words; dense returns near-misses | recall@k(sparse) – recall@k(dense) | Hybrid search |
| 4 · Chunk boundary | Answer exists; no single chunk is a good match | answer-in-one-chunk rate | Chunk boundaries |
| 5 · Top-k cutoff | Absent at production k; appears when k is raised | recall@50 – recall@k | Top-k / reranker |
The cheapest miss to confirm is also the one smoke tests never catch: the file exists in the CMS or filesystem, but the vector store has no searchable row for it. That is cause 1, and it decides whether retrieval ever had a chance.
The document is on disk but not in the index
The cheapest miss to confirm, and the one smoke tests never catch: the file exists in your CMS or filesystem, but the vector store has no searchable row for it. Retrieval cannot return what was never a candidate. Barnett et al. (2024) call the broader case Missing Content when the answer is not in the available documents at all; the operational subcase here is that the answer was never ingested into the store you are querying.
Non-Brand Data’s pitfall 2 (outdated or incomplete knowledge base) states the same constraint in corpus language: missing or outdated data leads to vague or inaccurate answers because the system can only retrieve indexed content. Label Studio’s Failure 1 fix list starts with ensuring the knowledge base is complete and up to date for the same reason. Direct ID lookup is what turns that advice into a binary check.
Symptom
Operators open the policy PDF and point at the paragraph. Every RAG query about that paragraph returns unrelated chunks, or nothing useful, and the document ID never shows in retrieval logs.
Detection
Look up the document ID or source path directly in the index. If index.contains(doc_id) is false, stop tuning retrieval.
Cause
Ingest skipped the file, the parser failed silently, the doc landed in the wrong namespace, or a delete path removed vectors without a re-add.
Fix
Re-run ingest for that source and verify the ID is searchable with a direct lookup before you touch embeddings or prompts. If the document was indexed and later drifted or was orphaned, that is stale index, not a first-time miss.
When the ID lookup succeeds and the document is still invisible under production queries, the next cheap confirmation is whether a metadata filter removed it before ranking ran.
A filter is silently excluding the right document
A metadata filter that is correct on paper and wrong in practice removes the gold document from the candidate set before ranking runs. The index looks healthy; every filtered query still misses. Non-Brand Data’s pitfall 6 (ignoring metadata and contextual signals) warns that pure vector search treats all documents equally and misses cues such as type, recency, or category; the failure mode here is the inverse misuse: filters that over-constrain and drop the gold row.
Chirag’s technical-document RAG write-up (Medium, captured September 2026) puts metadata filters inside query intelligence as a deliberate step after expansion. That design helps when tags are accurate. When tags or query-time filters disagree, the same step becomes the silent exclusion the filter check isolates.
Symptom
The document is indexed and well-embedded. It never appears for any phrasing while production filters stay on.
Detection
Re-run the identical query with every metadata filter removed. If the gold document appears, a filter was excluding it. Measure recall(no-filter) – recall(with-filter).
Cause
Tenant, department, language, date, or permission tags on the document do not match the filters applied at query time, or the tags themselves are wrong.
Fix
Audit query-time filters against the document’s metadata. The mechanism page is how metadata filtering works. This is the inverse of tenant leakage, where a missing filter admits the wrong documents.
If filters are innocent and the ID exists, the next discriminator asks whether the miss is lexical: the query’s surface form never matched the document’s words under dense-only search.
Why do the query’s words miss the document’s words?
Dense retrieval encodes meaning, but when the signal is the surface form (an acronym, a synonym the docs never use, a product ID, an exact policy title) the embedding blurs it and the right document never enters the candidate set. Non-Brand Data’s pitfall 7 (over-reliance on a single retrieval method) states that vector search can miss exact or specific matches such as error codes or rare terms, and recommends combining semantic and lexical channels.
Chirag’s dual-index design stores a BM25 lexical index beside the vector ANN index for the same reason. Weaviate’s hybrid search documentation (as of September 2026) describes the same pairing inside one collection: an inverted index for BM25 scoring next to the vector index, with a single hybrid query that fuses both. In that documentation, alpha of 1 is pure vector search and alpha of 0 is pure keyword search; if you do not set alpha, the effective weighting depends on the client. Relative Score Fusion is the default fusion method starting in Weaviate v1.24. When naming engines that ship both channels, Weaviate leads, then Elasticsearch, OpenSearch, Qdrant, and Azure AI Search.
Symptom
The user asks “PTO carryover after 90 days”; the handbook says “unused leave accrual past probation.” Same rule, few shared tokens: dense retrieval returns adjacent policies, never the gold file.
Detection
Re-run the identical query with BM25 only. If sparse finds the gold document and dense does not, vocabulary was the gap. Measure recall@k(sparse) – recall@k(dense); a positive gap is the tell.
Cause
Dense-only retrieval has no lexical channel, so exact-term and rare-token queries fall through even when the document is indexed.
Fix
Add the lexical signal: run BM25 alongside the embedding retriever and fuse the results via Combining BM25 and Vector Retrieval. The lexical baseline is BM25; the dedicated failure write-up is vocabulary mismatch. When the user’s phrasing never matched the document, query rewriting and expansion is the complementary fix on the query side.
Vocabulary can be fine and the document still absent from candidates when fixed-length splits cut the answer so neither chunk alone is a good match. That is a chunk-boundary recall miss, not a synonym problem.
The answer is split across two chunks
Sometimes the document is indexed and the vocabulary matches, but fixed-length splits cut the answer so neither chunk alone is a good match for the query. From the retriever’s point of view the document might as well be missing. Non-Brand Data’s pitfall 1 (poor chunking) names splitting a table or paragraph in the middle as a cause of nonsensical fragments and lost context; Barnett et al. (2024) likewise flag chunking quality as a driver of retrieval success in their lessons on embeddings.
Chirag’s dual chunking strategy (structure-first ingestion plus overlapping or hierarchical units) is one production response to that split. Mechanism depth for size, overlap, and parent retrieval lives on the chunking leaves; the job here is only to prove the boundary caused the candidate-set miss.
Symptom
Grep finds the answer in the source file. No retrieved chunk contains the full fact; near-miss chunks from other sections fill top-k instead.
Detection
Locate the answer string in the source and compare it to your chunk boundaries. Measure the answer-in-one-chunk rate on a labelled set: how often the full answer lives inside a single chunk.
Cause
Token-count splitting ignores meaning, so the sentence that answers the question lands on the wrong side of a boundary, or is diluted across two undersized fragments.
Fix
Diagnosis stops here. Tuning lives at chunk size and overlap; the dedicated failure mode is when the answer is split across two chunks. If a near-wrong chunk was returned, switch to the wrong-chunk differential.
When grep shows the answer inside one intact chunk and sparse and dense both find that chunk at a low rank, the remaining gate is the production cutoff: raising top-k makes the document appear.
Raising top-k makes the document appear
Barnett et al. (2024) name this Missed the Top Ranked Documents: the correct document exists in the store, but the retriever never ranks it high enough to enter the top-k fed to the model. Raising k “fixes” the demo and proves the document was a low-ranked candidate, not absent. Label Studio’s Failure 2 (March 2025) restates the same pattern and points at ranker and reranker tuning, plus checking whether key documents appear in the top-k results.
Non-Brand Data’s pitfall 8 (retrieving too many or too few documents) frames the balance: if k is too low, key evidence is missed; if k is too high, noise and context limits rise. Their practical note is to widen retrieval as a diagnostic, then narrow to a short relevant list, not to leave production k permanently huge. That matches the fix shape below.
Symptom
At production k the gold document is absent. At k=50 it appears at a rank greater than production k. Similarity thresholds that are too aggressive produce the same pattern.
Detection
Set top-k to 50 and re-query. If the gold document appears only then, you have a cutoff or ranking problem. Measure recall@50 – recall@k.
Cause
First-stage similarity is a coarse sort; a weakly related neighbour outranks the exact document, or production k is simply too narrow for hard queries.
Fix
Widen k as a diagnostic, then fix ranking: tune how many chunks you retrieve and add a cross-encoder reranker. A permanently huge k is not the production fix. When a wrong neighbour is what actually reached the model, see why the wrong chunk returned.
Once you can name the cause, you still need a meter that survives the next release: recall@k on queries paired with a known gold document, so a missing-document regression cannot hide behind a fluent answer.
How do you measure that retrieval missed the document?
The metric that names this failure is recall@k (and its RAGAS cousin, context recall) on queries paired with a known gold document: at a given k, did that document appear in the retrieved set? A zero means it was never a candidate. Worked definitions, formulae, and how recall relates to precision, MRR and nDCG live on measuring retrieval; here only the pass/fail reading matters.
Barnett et al. (2024) takeaway for practitioners is blunt: validation of a RAG system is only feasible during operation, and robustness evolves rather than being designed in at the start. Their BioASQ experiment indexed about 15,000 documents and ran 1,000 question-and-answer pairs through GPT-4 with OpenAI evals plus manual inspection to surface failure patterns. Label Studio’s Failure 1 fix list likewise includes human-in-the-loop validation to spot coverage gaps. Build a small labelled set of queries whose gold documents you can name, run recall@k before and after each change, and refuse to trust a smoke-test chat. When recall is low and you still do not know which pipeline stage failed, follow the decision procedure on RAG debugging.
Thresholds are local
Do not import someone else’s “good” recall number as a universal constant. Calibrate pass/fail on your own labelled queries and corpus; then track the same metric over time so a missing-document regression cannot hide behind a fluent answer.
The measurement closes the loop the proving sequence opened: index lookup, filters, top-k, sparse versus dense, and chunk boundaries each map to a cause, and recall@k is how you know the cause stayed fixed after the next ingest or model swap.
A missing-document failure is settled only when the gold file is searchable, survives production filters, ranks inside the window you actually pass to the model, and still appears under the phrasings your users type. Prove absence from the candidate set first, name the gate with one discriminating measurement, then change that gate alone. Generation-side failures and wrong-chunk returns are different chapters; this one ends when the document you already knew was there finally shows up in retrieval logs at a rank the generator can see.
- Chunk boundary loss
- Conflicting sources
- RAG debugging
- Retrieval quality degradation
- Enterprise RAG failure
- Hallucination despite context
- RAG latency
- Multi-tenant leakage
- Lost in the middle
- Missing the obvious document
- Multi-hop questions
- Stale index
- Numbers and tables
- Vocabulary mismatch
- Wrong chunk retrieved