Why did it abstain?
A refusal is a successful outcome — it is the product working. But “I can’t answer that from the available evidence.” is the same sentence for several different situations, and reaching for the wrong fix wastes a day.
Every refusal says why. Read two things:
response = rag.ask("Can the employee disclose this?")
print(response.evidence.decision) # Decision.refusedprint(response.missing_evidence) # ← the reason, in wordsprint(response.evidence) # ← the structured signalsimport "github.com/muthuishere/citenexus/golang/answer"
res := answer.Ask(corpus, "Can the employee disclose this?", answer.DefaultTopK)
fmt.Println(res.Evidence.Decision) // result.DecisionRefusedfmt.Println(res.MissingEvidence) // ← the reason, in wordsfmt.Printf("%+v\n", res.Evidence) // ← the structured signalsimport { ask } from "@muthuishere/citenexus";
const res = ask(corpus, "Can the employee disclose this?");
console.log(res.evidence.decision); // Decision.refusedconsole.log(res.missing_evidence); // ← the reason, in wordsconsole.log(res.evidence); // ← the structured signalsOnly the producing line differs: Python retrieves from a store, the ports answer over an in-memory corpus. The refusal fields are the same three, in all three.
missing_evidence is a tuple of strings on Result. evidence is the
EvidenceSignals object. Between them, every refusal below is distinguishable
without guessing.
The index
Section titled “The index”| What happened | missing_evidence[0] starts with |
Field to check |
|---|---|---|
| Nothing relevant enough was retrieved | no sufficiently relevant evidence found |
— |
| The generated answer didn’t follow from the passage | generated answer failed the faithfulness gate |
all_claims_verified |
| Nothing cleared the authority floor | no evidence at or above the required authority tier |
authority_floor_applied is True |
| The question’s script isn’t claimed | unsupported script: |
unsupported_scripts is non-empty |
| Every candidate document’s script isn’t claimed | no readable evidence found; unsupported script: |
unsupported_scripts is non-empty |
| Strict mode, and the sources contradict each other | cited sources disagree and the conflict is unresolved |
conflicts_detected > 0 |
The last one is the only refusal that does not use the pinned refusal string:
it answers with “The available evidence disagrees, so I can’t answer that.” and
returns both sides in sources.
1. No sufficiently relevant evidence
Section titled “1. No sufficiently relevant evidence”
missing_evidence = ("no sufficiently relevant evidence found",)
Retrieval returned candidates, but none of them shared enough with the question to be worth generating from. This is the most common first-run refusal and it is almost always a retrieval problem, not an answering one.
Work down this list:
- Is anything actually indexed?
rag.retrieve(question)returns documents without generating. Empty means ingest, not answering, is the problem. - Did you declare an
embeddingsignal but inject no embedder? Then dense retrieval is silently absent and you are running on BM25 alone — which cannot bridge a paraphrase. See Signals & capabilities. - Is the question in a different script from the corpus? BM25 overlap between
two scripts is zero. See Languages and
search_languages. - Is
ktoo small? Raise the per-call cutoff:rag.ask(question, k=20). See Reranking & retrieval.
2. The answer failed the faithfulness gate
Section titled “2. The answer failed the faithfulness gate”
missing_evidence = ("generated answer failed the faithfulness gate", ...)
Retrieval did find a relevant passage. The model generated from it, and what it generated did not follow from it — wrong order, a dropped negation, or an assertion the passage does not make. The gate rejected it rather than emit a verbatim-sourced falsehood.
The flow tries up to five candidate passages before giving up, so this refusal means every attempt failed.
“Every atomic claim was dropped” is this same refusal. Claims are gated
individually and a failing claim is dropped, not fatal — an answer keeps its
surviving claims and records the casualties in unsupported_claims_removed. Only
when nothing at all survives does the call refuse, and it refuses with this
string. There is no separate “all claims dropped” signal, and partial drops never
refuse. Check all_claims_verified and unsupported_claims_removed on your
answered results to see how often claims are being trimmed.
What to do:
- This is usually the right answer. Read the retrieved passage yourself: more often than not, it genuinely does not support the question.
- Your generator may be paraphrasing too freely. An extractive generator — one that returns the source’s own sentences — clears the gate reliably; a chatty one will not.
- If the passage does support the question and the gate still rejects, the claim
is likely compressed beyond the pinned
(4, 8)gap budget, or its polarity markers do not survive. See The faithfulness gate.
3. Nothing met the authority floor
Section titled “3. Nothing met the authority floor”
missing_evidence = ("no evidence at or above the required authority tier",)
evidence.authority_floor_applied is True
Grounded evidence existed, and it was excluded on standing — a Florida statute retrieved for a Texas question, an unpublished note where a controlling source was required. This is not “there is no evidence”; it is “what I found has no standing here”, and conflating the two is exactly how an out-of-jurisdiction citation hides behind 100% groundedness.
authority_floor_appliedisTrueonly when the floor actually excluded something. On an unranked corpus it staysFalseand this refusal cannot occur.- Fix by curating: attach
authority=metadata at ingest for the sources that do have standing, or lower the floor if it was set too high. - Full reference: Authority — source standing.
4 & 5. The script is not claimed — a capability gap, not a judgement
Section titled “4 & 5. The script is not claimed — a capability gap, not a judgement”
evidence.unsupported_scriptsis non-empty
This is the distinction that matters most on this page. Every other refusal here is a statement about your evidence. This one is a statement about CiteNexus: the tokenizer does not claim to segment this script, so the library cannot read the text — and it says so rather than reporting an absence of evidence it never actually looked for.
Returning “no evidence found” for a capability gap is precisely what let an
ASCII-only tokenizer hide for a whole release. Never treat a non-empty
unsupported_scripts as “my corpus doesn’t cover this”.
Two forms:
- The question is unreadable —
missing_evidence[0]is"unsupported script: …". Nothing was even retrieved. - The whole candidate pool is unreadable —
"no readable evidence found; unsupported script: …".
And one non-refusal worth knowing: if some candidates are readable, the call
answers, and the unreadable ones are reported additively —
unsupported_scripts is still populated and missing_evidence carries a note
like "2 candidate document(s) could not be read and were excluded: …". A
successful answer with a non-empty unsupported_scripts means part of your
corpus was invisible to that query. Monitor it.
Fix: nothing you configure. Check the claimed-script table on Languages; an unclaimed script needs tokenizer support, which is a library change, not a knob.
6. Strict mode, and the sources disagree
Section titled “6. Strict mode, and the sources disagree”
answer = "The available evidence disagrees, so I can't answer that."
missing_evidence = ("cited sources disagree and the conflict is unresolved",)
evidence.conflicts_detected > 0
Two retrieved passages contradict each other and the contradiction touches the
passage that would have been cited. Strict mode refuses and returns both
sides in sources rather than letting rank silently pick a winner.
- This refusal really is the same in all three: detection is native in Python, Go and JavaScript, from one predicate pinned by 132 committed vectors.
- In Python,
normalmode answers and lists the conflicts instead of abstaining, andexploratoryrecords the count only. Go and JavaScript definestrictalone, so they always take the abstention above. - Conflicts are never resolved by ranking. If one source really is authoritative, say so with authority metadata — that is the signal that can break the tie legitimately.
- Full story: Conflicting sources.
A refusal is not always a bug
Section titled “A refusal is not always a bug”The three guards you are most likely to want to keep refusing are the faithfulness gate, the authority floor and the conflict abstention. If you are tuning to make refusals go away, tune retrieval (cause 1) first — the other five are usually telling you something true.
- The faithfulness gate
- The Result object — every field named here
- How it works — where each guard sits in the pipeline