Fault injection tooling is built to break things loudly. The Agent Error Simulator intercepts agent-to-model HTTP traffic and injects format, logic and tool-call faults at chosen points in a planner-worker-aggregator workflow, then measures whether the workflow recovers Agent Error Simulator. That design is excellent at answering "what happens when a tool returns a 500 or a number arrives as a string". It cannot answer "what happens when the tool returns 200 with a plausible number that is wrong".
The reason is structural. Multi-agent systems coordinate in unstructured natural language rather than rigid protocols, so they are prone to semantic failures such as hallucinations, misinterpreted instructions and reasoning drift that propagate silently without raising runtime exceptions MAS-FIRE. When instructions travel as prose, there is nothing for a schema validator to reject. A JSON body that parses is treated as success.
Production teams see the same shape. Observability vendors describe agents that complete a workflow, return a response and produce output that looks correct until downstream consequences reveal the error, often hours later Latitude. One concrete example from the same taxonomy: a bad tool argument at step two silently corrupts every later step that depends on it.
A second research thread makes the case worse. A study of more than 40,000 controlled trials and 100,000 production interactions found failures occurring with static prompts, identical models and fixed databases, with no external trigger at all Silent Failure in LLM Agent Systems. These are ordering failures, not bugs, and they accumulate with interaction rounds.
The decision rule that follows is straightforward: fault injection tests the transport and the tool contract; it does not test meaning. If your only gate between agents is a schema check, you have tested the envelope and ignored the letter.
The fixture set: seeds from real bad outputs
Before you write a verifier, write down what "bad" looked like. A fixture set is a versioned file of inputs paired with the known-bad output and a label for why it is bad. It is the cheapest artifact in the whole system and the only one that keeps the hop honest.
Gather fixtures from three places:
- Incident tickets. Every time someone says "the agent told a customer the wrong thing", capture the request, the raw producer output and the correct answer.
- Reviewer overrides. When a human reviewer edits or discards an agent's draft, the discard is a fixture.
- Deliberate near-misses. Ask the producer model to answer questions just outside its data, then save the confident replies.
Each fixture needs a label, not just a verdict, because the label drives the routing decision later. Use a small taxonomy:
| Label | What it looks like | Typical origin |
|---|---|---|
fabricated_entity | Names a record, person, order or SKU that does not exist | Hallucinated identifier in step one of a chain |
stale_fact | Correct six months ago, superseded now | Cached retrieval, slow index refresh |
scope_creep | Answers a related question nobody asked | Misread instruction in a handoff |
unit_or_sign | Right number, wrong scale or direction | Arithmetic drift between worker and aggregator |
truncated | Ends mid-sentence, HTTP 200, missing the second half | Silent empty or partial tool response |
Store the fixture as a small record: input, producer output, label, expected behavior, and the ticket id. Keep it in the same repository as the verifier so that a change to the rule and a change to the expectation land in one review.
A useful sizing heuristic: five fixtures per label is enough to catch a regression in the verifier itself. Below that, a single edited fixture can flip a passing suite.



