{"record":{"id":"bc5d4fe5b14792d4","repo":"influxdata/influxdb","slug":"all-types-covered","errorCode":null,"errorMessage":"all types covered","messagePattern":"all types covered","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/panic_logging/src/lib.rs","lineNumber":194,"sourceCode":"impl Metrics {\n    fn new(metrics: &metric::Registry) -> Self {\n        let metric = metrics.register_metric::<U64Counter>(\n            \"thread_panic_count\",\n            \"number of thread panics observed\",\n        );\n\n        Self {\n            counters: PanicType::all()\n                .iter()\n                .map(|t| (*t, metric.recorder(&[(\"type\", t.name())])))\n                .collect(),\n        }\n    }\n\n    fn inc(&self, panic_type: PanicType) {\n        self.counters\n            .get(&panic_type)\n            .expect(\"all types covered\")\n            .inc(1);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::panic::panic_any;\n\n    use metric::{Attributes, Metric};\n    use test_helpers::{assert_contains, maybe_start_logging, tracing::TracingCapture};\n\n    use super::*;\n\n    fn assert_count(metrics: &metric::Registry, t: &'static str, count: u64) {\n        let got = metrics\n            .get_instrument::<Metric<U64Counter>>(\"thread_panic_count\")\n            .expect(\"failed to read metric\")\n            .get_observer(&Attributes::from(&[(\"type\", t)]))","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/influxdata/influxdb/blob/d28e26e048401c53cbb98cf2d6ab0cf1e98048ca/core/panic_logging/src/lib.rs#L176-L212","documentation":"panic_logging's PanicCounters builds a HashMap from PanicType::all() and inc() does counters.get(&panic_type).expect(\"all types covered\"). The map is populated from the same enum's all() list, so the lookup fails only if the PanicType enum and its all() implementation have diverged — i.e. a variant exists that all() does not return. This is a maintenance invariant: it fires on a variant that was added without updating all(), not on runtime data.","triggerScenarios":"A new PanicType variant added to the enum without extending PanicType::all(); any panic of that new type then panics here while incrementing its counter, replacing the very panic being logged. Also possible with a stale/inconsistent build mixing old and new crate artifacts.","commonSituations":"Contributing a new panic category to panic_logging; version-skewed incremental builds after rebasing; feature-gated variants compiled in one crate instance but not in the instance that built all().","solutions":["If you added a PanicType variant, add it to PanicType::all() (or replace the manual list with a match that has a wildcard/error arm).","cargo clean and rebuild to rule out stale artifacts mixing enum layouts.","Make the invariant un-breakable: derive the list (e.g. strum::EnumIter) or use a match returning the name with `#[deny(unreachable_patterns)]`.","Upstream-style hardening: fall back to an 'unknown' counter instead of expect so panic logging never panics."],"exampleFix":"// before\nfn all() -> Vec<PanicType> {\n    vec![/* manually maintained list; new variants silently missing */]\n}\n\n// after (compiler-enforced exhaustiveness)\nfn all() -> Vec<PanicType> {\n    // strum::EnumIter: `PanicType::iter().collect()`\n    // or a `fn name(&self) -> &str` match which fails to compile\n    // when a variant is added without a arm.\n    PanicType::iter().collect()\n}","handlingStrategy":"type-guard","validationCode":"// compile-time or startup-time exhaustiveness check when you touch PanicType\n#[test]\nfn panic_types_all_is_exhaustive() {\n    // requires an iterator derive (strum) or a match-based name():\n    // adding a variant without updating all() should fail here, not in prod\n    assert_eq!(PanicType::all().len(), EXPECTED_VARIANT_COUNT);\n}","typeGuard":"// if you maintain this crate: encode exhaustiveness in the type\ntype PanicCounters = EnumMap<PanicType, U64Counter>; // keyed by variant, cannot miss\n\n// or: fn counters() -> impl Fn(PanicType) -> U64Counter built from a\n// `match` with per-variant arms (a new variant breaks the build).","tryCatchPattern":null,"preventionTips":["When adding a PanicType variant, update PanicType::all() in the same commit.","Prefer strum EnumIter or a match-based name() so the compiler enforces exhaustiveness.","cargo clean after rebasing across changes to this crate to avoid stale-artifact mismatches.","Never let the panic-logging subsystem itself expect() — degrade to an 'unknown' counter instead."],"tags":["rust","internal-invariant","enum-exhaustiveness","panic-logging","maintenance-bug"],"backgroundTag":"unhandled-enum-variant","analyzedSha":"d28e26e048401c53cbb98cf2d6ab0cf1e98048ca","analyzedAt":"2026-08-16T19:53:34.623Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}