A Fallback That Looks Healthy Can Still Be Wrong
Suneet Malhotra
Sep 11, 2026
A fallback is not correct merely because it prevents an error from reaching the user.
In an AI workflow, a failed retrieval call might fall back to a cached answer. A model timeout might select a smaller model. A tool authorization failure might return a read-only explanation. Each behavior can be sensible. Each can also produce a response that looks healthy while silently changing what the system was able to know or do.
That is the failure mode worth testing: graceful degradation that preserves availability but loses meaning.
The response code is not the result
Traditional service tests often stop at a stable boundary. The request returned a 200 response. The JSON parsed. The latency stayed below the threshold. Those checks are useful, but an agent can pass all three while violating the product contract.
Imagine an assistant that answers questions about an internal runbook. The primary path retrieves the current document, adds its revision ID to the prompt, and produces an answer. When retrieval fails, the fallback asks the model to answer from its general training data. The endpoint still returns 200. The answer may be fluent and even plausible. It is no longer an answer grounded in the runbook.
The defect is not that the fallback exists. The defect is that the system has hidden the loss of evidence.
For QA, this means the assertion cannot be only status == 200. The test needs to inspect the decision trace and the user-visible contract. Which source was available? Which model ran? Did the system claim freshness it did not verify? Was a write action refused, or did the fallback pretend it completed?
Model the degraded path explicitly
I use a small state table before writing the test. It makes the fallback's obligations concrete.
| Condition | Allowed behavior | Required evidence |
|---|---|---|
| Retrieval succeeds | Answer from retrieved context | Source ID and revision |
| Retrieval times out | Answer only if the product permits stale context | Cache age and fallback reason |
| Retrieval returns no document | Say that evidence is unavailable | Empty-source state, no invented citation |
| Tool authorization fails | Explain the refusal or offer a read-only alternative | Policy result and attempted tool |
| Primary model times out | Retry or switch model under a named rule | Attempt count and model identity |
The important row is not the happy path. It is the boundary between an answer the system is authorized to give and one it merely knows how to phrase.
A fallback should have a declared semantic budget. It may preserve formatting, but not freshness. It may preserve explanation, but not execution. It may preserve a best-effort answer, but only if uncertainty is visible. If those tradeoffs are not written down, the implementation will choose them accidentally.
A practical test with synthetic evidence
Here is a compact scenario for an automated regression suite. Create two synthetic documents:
runbook-v1: "The service uses port 8443."runbook-v2: "The service uses port 9443."
Make the primary retriever return runbook-v2, then ask, "Which port does the current runbook specify?" Assert the answer contains 9443 and records the revision as v2.
Next, inject a timeout into retrieval. The expected result depends on the product contract, but it must be explicit. A strict assistant should refuse to claim the current port. A stale-cache design may answer 8443 while labeling the cache as v1 and its age. What should fail is an unqualified answer that says 9443, because the test has removed the evidence needed to support it.
Then inject a timeout into the primary model after retrieval succeeds. If the smaller fallback model is allowed to use the same context, the answer can remain valid, but the trace should identify the fallback model and the reason for the switch. If the fallback cannot accept the retrieved context, it must not silently answer as though it did.
The assertions should cover at least four surfaces:
- The answer: factual content and uncertainty language.
- The trace: retrieval status, source revision, model, attempts, and fallback reason.
- The action boundary: whether any tool call or write was attempted.
- The telemetry: a counter or event that lets an operator distinguish primary success from degraded success.
This is not testing the model's prose alone. It is testing whether the system preserved the meaning of its answer while its dependencies changed.
Observability must expose the downgrade
Many dashboards collapse primary and fallback responses into one success metric. That makes the system look more reliable as dependencies become less reliable. Availability rises on paper while evidence quality falls.
Track fallback rate separately from request success. Break it down by cause: timeout, empty retrieval, rate limit, authorization, and schema failure. Record the selected model and whether the response depended on cached or live context. Sample the decision trace with care for privacy, but do not remove the fields needed to explain the transition.
The useful alert is not always "fallback happened." Some fallbacks are expected. The useful alert may be "fallback answered freshness-sensitive questions" or "write-capable requests reached a read-only model without a refusal." Those alerts are tied to semantic risk rather than plumbing noise.
Test the boundary, not just the branch
There is a subtle difference between branch coverage and contract coverage. A unit test can execute the timeout handler and confirm that it returns a response. That proves the branch is reachable. It does not prove that the branch preserves the rules that matter to a user.
For each fallback, add at least one invariant that must remain true and one capability that must become false. For example, a cached retrieval may preserve the document's last known text, but it must lose the claim that the text is current. A smaller model may preserve a classification schema, but it may lose permission to call tools. A read-only mode may preserve explanations, but it must not create an order, update a ticket, or send a message.
These paired assertions are easier to maintain than a large collection of example answers. The invariant describes the contract. The lost capability describes the safety boundary. The wording can change without making the test meaningless.
Also test recovery. After the dependency returns, the next request should use the primary path again, unless the system deliberately has a circuit breaker with a documented reset policy. A common bug is a sticky fallback: one transient timeout changes a process-level client, and every later request quietly uses the degraded path. The response remains valid enough to avoid an obvious outage while quality and freshness drift for hours.
The recovery test should therefore send requests in sequence: primary success, injected failure, fallback response, dependency recovery, primary response. Assert the route taken for every request. A fallback is part of a state machine, not an isolated exception handler.
The checklist
Before shipping a fallback, ask:
- What capability is lost when this path runs?
- What claims must the fallback refuse to make?
- Can the user tell that the system degraded?
- Does the trace identify the cause, model, source, and attempt count?
- Are side effects disabled or reconciled when execution becomes uncertain?
- Does monitoring separate degraded success from primary success?
- Is there a test that removes the evidence behind the most dangerous claim?
A healthy-looking response is an observation about transport. Correctness is an observation about the contract. Agent QA needs both. The fallback earns its place when it keeps the system useful without pretending that an unavailable dependency was available.
Share this post
You Might Also Like
Test AI Latency from First Token to Finished Answer
A fast first token can hide a late or invalid answer. Test queueing, streaming, and completion with a synthetic workload before accepting a model-serving change.
AI & AutomationTest the Trace Before You Trust the Dashboard
A correct AI answer can hide a broken trace. Use a synthetic request and a deliberately stripped context header to test whether your debugging evidence survives service boundaries.
Career & Best PracticesThe Cheapest Test Is the One You Run Before You Build
The most expensive engineering mistakes in my systems were not hard bugs. They were reasonable implementations of questions nobody had defined.
Quantitative TradingA Signal Is Not a Decision
A signal says that conditions are interesting. It does not say that the portfolio should trade. The missing layer is the decision record between detection and execution.
Latest Blog Posts
Test AI Latency from First Token to Finished Answer
A fast first token can hide a late or invalid answer. Test queueing, streaming, and completion with a synthetic workload before accepting a model-serving change.
Test the Trace Before You Trust the Dashboard
A correct AI answer can hide a broken trace. Use a synthetic request and a deliberately stripped context header to test whether your debugging evidence survives service boundaries.
The Evaluator Needs an Abstain State
A judge that must choose pass or fail will turn uncertainty into false confidence. Add an abstain state, calibrate it, and test the cases where the evaluator should refuse to decide.
Related Tools & Demos
The QA Field Manual to Language Models
A free 24-chapter book. Start at βwhat is AI, really?β and finish with a small language model you built yourself β one that reads a failing Playwright test and proposes a fix you can run. Read it in your browser, or download the PDF or the Mac app.
View Source Code βMulti-Model LLM Harness
One interface to call any AI model β capability routing, fallback chains, budgets, circuit breakers, and a quality feedback loop. A practical architecture pattern write-up.
Automated Trading System
Multi-engine trading platform with real-time risk management, regime-based strategy selection, and automated order execution.
View Source Code β
Stay in the Loop
Get weekly insights on AI-driven QA, engineering leadership, and automation strategies.
No spam, ever. Unsubscribe anytime.