Many of the most damaging bugs in CLI coding agents are not crashes but silent failures: runs that exit 0, produce plausible-looking output, and print nothing to stderr while the user's intent was not honored. This page distills two such classes surfaced in the Claude Code changelog (2.1.299–2.1.300) and probed against yoyo v0.2.0 (commit 643713dc), where both failure modes were reproduced. The lesson generalizes: a single fix on one code path ("one door") does not protect the parallel path ("another door") where the same condition is still swallowed.
Key Points
Invalid input must never be silently accepted. If a settings/config value fails validation, the run should name the offending file and the invalid entry on stderr — even in text-output (-p) mode.
Two doors, one deaf. A warning wired into one entry point (e.g. the --flag CLI form) does nothing for the other (e.g. the config-file fallback) if the latter uses a silent parse. Every path that accepts the same value needs the same validation.
Truncation is a failure, not a finished turn. When a reply is cut off at the output-token limit, ending the turn with no retry, no error, and exit 0 hides a real loss of output.
Related fail-silent risks worth remembering: hook allow overriding a mode refusal, symlinked sandbox deny paths, silent transcoding of non-UTF-8 files, and deny rules that miss client names containing double underscores.
Stale defaults hide in plain sight when presets and provider defaults are maintained as separate sources of truth.
Concepts
Silent failure — a condition (invalid config, truncated output) that should be surfaced but instead yields a normal-looking success.
Config fallback path — the .and_then(|s| s.parse().ok()) pattern that discards a parse error instead of reporting it.
— mapping a model's stop reason (e.g. ) to an action (retry, error, or ignore).
Stop-reason classification
Length
Hook/mode precedence — whether a PreToolUse hook's allow can override a mode's refusal (it must not).
Option precedence between presets and provider defaults.
Details
1. Config validation that says nothing
The upstream fix: claude -p no longer stays mute when a settings file fails validation — text-output runs now list the file and the invalid entry on stderr.
Probed against yoyo: injecting bad values into .yoyo.toml all ran with exit 0 and no stderr output:
max_tokens="lots" (non-numeric)
context_window=-5 (out of range)
an unclosed [permissions section header
a typo key modle="x"
The only value that warned was thinking="galactic".
Root cause: in cli.rs, parse_numeric_flag warns for the --flag form of a value, but the config-file fallback uses .and_then(|s| s.parse().ok()), which silently drops the parse error. This applies to max_tokens, temperature, max_turns, and context_window. The flag path and the config path accept the same value — but only one of them reports when it is bad.
2. Replies cut off with no notice
The upstream fix: replies cut off at the output-token limit, in a request that had fallen back to non-streaming mode, previously ended the turn silently with no retry or error.
Probed against yoyo: yoyo --max-tokens 30 -p "numbers 1 to 200" printed only 1..15, then exited 0 with no notice.
Root cause:classify_stop_reason in prompt_retry.rs maps StopReason::Length to Ignore; nothing else in src matches StopReason::Length. So the single place that could react to truncation explicitly discards it.
Rendering diagram…
3. Other fail-silent risks to remember
Hook allow vs. mode refusal — plan mode ran a write that a PreToolUse hook allowed. A hook allow must not override a mode's refusal.
Sandboxed deny paths via symlink — a symlink can route around a deny path (addressed as yoyo issue #998).
Silent transcoding — Write silently transcoded non-UTF-8 files; now refused.
Observed separately: yoyo's default models look stale. providers.rs's default_model_for_provider returns claude-opus-4-6 (anthropic), gpt-5 (openai), and gemini-2.5-flash (google), while the presets already know opus 5.5 and gpt-6-*. Provider defaults and presets drift apart when they are separate sources of truth — a quieter class of staleness, but the same theme of discrepancies that no run surfaces to the user.