ErrLookup › Background articles › "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained
"This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained
Errors like RxDB's SNH ("should not happen"), k6's "this is a bug in k6 please report it", Delve's "internal debugger error", and Rust expect("...") panics are internal invariant violations: checks that library authors place on states their code should never be able to reach. This article explains what layer produces them, why a well-formed request or normal configuration almost never triggers them, and how to tell a genuine library bug from a fork, plugin, or version mismatch that broke the invariant from outside.
Distilled from 103 documented records across 47 repositories.
Background
Every mature library contains code the authors believe is unreachable: an expect() on an Option that a preceding branch already filled, a match arm for an enum combination that cannot occur, a counter that must agree with a queue length. Libraries encode these beliefs as explicit assertions — Rust's expect and panic!, Go panics with "internal debugger error", RxDB's SNH error code, nginx ALERT-level log messages like "recycled buffer in pipe out chain", or Java IllegalStateException. Unlike validation errors, these checks do not correspond to any bad input the caller can supply. They exist so that, when an assumption silently rots, the library fails loudly at the exact spot instead of corrupting state downstream.
The mechanism is always the same: some earlier code path establishes a fact (the executor was initialized, the response is the Initial variant, the status was assigned before the loop exits, the files array length bounds the index), and the assertion re-checks that fact at the point of use. mise's bootstrap code is a textbook case: configured_accounts is computed as Some whenever a flag is true, and a later unwrap asserts that implication still holds. RxDB's categorizeBulkWriteRows expects every successfully written row to be classifiable as INSERT, UPDATE, or DELETE; anything else means its assumptions about storage are broken. These guards fire for two reasons: the internal code drifted (a refactor added a break without assigning the status variable, a new enum variant skipped clap wiring), or an external component broke the contract (a custom RxStorage returning inconsistent rows, a forked Ollama provider overriding convert_tools while native tools stay disabled, a third-party nginx filter module recycling output buffers).
From the caller's side, these errors look alarming because they usually arrive as a panic, an HTTP 500 (litellm's unreachable ValueError in GET /v1/batches escapes as an unhandled server error), or a process-level abort with a backtrace rather than a friendly message. The message itself is the tell: phrases like "should not happen", "SNH", "this is a bug in k6 please report it", "(parser bug)", "internal debugger error", or a bare "System failure" mark the branch as internal. Some libraries embed debugging aids in the error — Delve's depth checks append the compiled instruction Listing, RxDB attaches the offending writeRow to err.parameters, Argo names the missing podName — precisely because the maintainers expect these reports to arrive as bug tickets.
Across libraries the family varies mainly in strictness and audience. Rust-heavy projects (mise, influxdb, tikv, linera) lean on expect/unwrap with prose messages addressed half to users and half to contributors; the fix guidance often includes what a contributor must do to restore the invariant. JavaScript and Go projects tend to use named error codes (RxDB SNH) or panic strings with explicit reporting instructions (k6, delve). Systems software (nginx) surfaces the same class as an ALERT log line rather than a crash. What does not vary: none of the 30 best-documented records can be triggered by ordinary, well-formed usage of a stock build. When one fires, the first question is always whether you are actually running stock code at the expected version.
Common causes
- Version mismatch or stale artifacts. Flags, binary result files, or cached payloads produced by one library version are consumed by another: Bevy compression flag bits round-tripped across versions, Gradle test results merged from different versions into one report, RxDB plugins or custom storages not matching core, OBS SDK and hadoop connector drift, or a stale-format cache in an MCP/protocol client. The invariant assumed one version's bit layout or schema.
- Forks, wrappers, and modified builds. A patched or wrapped component broke the contract while keeping the guard: zeroclaw forks enabling Ollama tool conversion without native-tools support, patched Argo or linera faucet builds, wrapper code that mutates args between a preflight and execute validation. The message is the fork disagreeing with upstream's assumptions.
- Third-party plugins and extension modules. Code the library loads but did not write violates its internal contract: an nginx body filter that recycles chain buffers found in the output chain, a custom RxStorage returning bulkWrite results with inconsistent previousDocument/deleted flags, a misregistered capability tool in SiYuan with no handler attached.
- Internal regression in the library itself. A refactor broke a previously sound implication: a new select-loop break that skips assigning the wait status in mise, a new enum variant without ValueEnum wiring, a call site moved before setup_executor runs, or an untested expression shape in Delve's compiler pushing and popping the stack asymmetrically. These are genuine library bugs to report upstream.
- Concurrent or double use of single-owner state. State meant to be touched exactly once, or from one thread, was touched twice: tikv double-completing a ReadIndexRequest so ready_cnt desyncs from the queue, influxdb dictionary builders mutated from multiple threads, Argo's podNames and groupedByPod maps diverging under interruption, litellm request state changing between check and assignment.
- Race or inconsistent results from a lower layer. The storage or OS layer returned data violating an ordering or consistency assumption, as in Hadoop's depth-sorted directory deletion receiving objects not sorted by path depth — often transient, sometimes an SDK behavior change.
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Documented occurrences
- Color compression flag must be `COMPRESS_COLOR_FLOAT16` or `COMPRESS_COLOR_UNORM8` (bevyengine/bevy)
- target_model_names is required for this routing scenario (BerriAI/litellm)
- Ollama returned non-prompt-guided tools payload while native tools are disabled (zeroclaw-labs/zeroclaw)
- command wait must complete (jdx/mise)
- If we can remove a value from the interned strings, we must also be able to remove a value from the packed strings. (influxdata/influxdb)
- pr://${repo}/${parsed.number}/diff/${index} resolved to a missing slice (parser bug). (can1357/oh-my-pi)
- SNH: RxDB Error-Code: ${message}. Hint: Error messages are not included in RxDB core to reduce build size. To show the full error messages and to ensure that you do not make any mistakes when using RxDB, use the dev-mode plugin when you are in development mode: https://rxdb.info/dev-mode.html?console=error Find out more about this error here: https://rxdb.info/errors.html?console=errors#SNH Still stuck? Ask in the RxDB Discord: https://rxdb.info/chat (pubkey/rxdb)
- System failure (apache/hadoop)
- enabled accounts were prepared (jdx/mise)
- configured notifications came from managed files (jdx/mise)
- NGX_LOG_ALERT: recycled buffer in pipe out chain (nginx/nginx)
- must have offset (influxdata/influxdb)
- Multiple assumption failures would need to be handled, but only one is supported: {} (gradle/gradle)
- system files were preflighted when not skipped (jdx/mise)
- executor must be initialized before displaying cache stats (jdx/mise)
- BootstrapPart values have clap names (jdx/mise)
- plugin task name should be registered before spawning (jdx/mise)
- Unexpected response type (linera-io/linera-protocol)
- switch_monitor input preflight did not run. (koala73/worldmonitor)
- capability handler unavailable: %s (siyuan-note/siyuan)
…and 83 more across the corpus — use search.
Honest provenance: generated on 2026-09-04 from AI-assisted analysis of the linked records. See how records are made.