pydantic/monty · error

unreachable

Error message

unreachable

What it means

An `unreachable!()` panic in monty-apidoc's `render_impls`: items sorted into the `inherent` bucket are assumed to be `ItemEnum::Impl` rustdoc items. If any other item kind lands in that bucket, the assumption is broken. This affects documentation rendering only, not the interpreter.

Solutions

  1. Update the match/filter in `render_impls` to handle the new rustdoc JSON item kind.
  2. Pin or update rustdoc-json-related tooling to a version consistent with the parser in monty-apidoc.
  3. Run `make generate-api-docs` locally on the failing rustc version and inspect the unexpected item.

Example fix

// before
let ItemEnum::Impl(impl_) = &impl_item.inner else {
    unreachable!()
};
// after
let ItemEnum::Impl(impl_) = &impl_item.inner else {
    continue; // skip non-impl items gracefully
};
Defensive patterns

Strategy: fallback

Try / catch

// Treat non-impl inherent items as skippable instead of panicking
let Some(impl_) = match &impl_item.inner {
    ItemEnum::Impl(i) => Some(i),
    _ => None,
} else { continue };

Prevention

When it happens

Trigger: Rendering API docs when a rustdoc JSON item grouped as `inherent` is not an `Impl` — e.g. after a rustdoc-json format change or a mis-filtered match arm upstream in `render_impls`.

Common situations: Hit when regenerating docs (`make generate-api-docs`) after a rustc/rustdoc-json version bump that adds new ItemEnum variants or changes impl grouping.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/b012dc0c61c96047. Report an issue: GitHub.

Appendix: source

Thrown at crates/monty-apidoc/src/render.rs:191

        let mut traits: Vec<String> = Vec::new();
        for impl_id in impls {
            let impl_item = &self.krate.index[impl_id];
            let ItemEnum::Impl(impl_) = &impl_item.inner else {
                continue;
            };
            match &impl_.trait_ {
                None => inherent.push(impl_item),
                Some(trait_) => {
                    if !impl_.is_synthetic && !impl_.is_negative && impl_.blanket_impl.is_none() {
                        traits.push(to_plain(&self.sig().path_str(trait_)));
                    }
                }
            }
        }
        inherent.sort_by_key(|item| item.span.as_ref().map(|s| (s.filename.clone(), s.begin)));
        for impl_item in inherent {
            let ItemEnum::Impl(impl_) = &impl_item.inner else {
                unreachable!()
            };
            self.render_methods(out, name, impl_, level);
        }
        traits.sort();
        traits.dedup();
        if !traits.is_empty() {
            let list: Vec<String> = traits.iter().map(|t| format!("`{t}`")).collect();
            writeln!(out, "\nImplements: {}.", list.join(", ")).unwrap();
        }
    }

    /// The methods (and associated consts) of one inherent impl block.
    fn render_methods(&self, out: &mut String, type_name: &str, impl_: &Impl, level: usize) {
        for method_id in &impl_.items {
            let method = &self.krate.index[method_id];
            let Some(method_name) = method.name.as_deref() else {
                continue;
            };

View on GitHub (pinned to adc986b362)