rust-lang/rust · critical

Failed to get parent for {child:?}

Error message

Failed to get parent for {child:?}

What it means

This panic fires in specialization_graph.rs:45 inside `Graph::parent`, which looks up the immediate parent of an impl in the per-trait specialization tree (`DefIdMap<DefId> parent`). The map is populated during coherence graph construction, so a missing entry means an impl DefId was queried for its parent before (or without) being registered into the graph — an internal compiler invariant violation, not user code. It is reached through specialization/coherence machinery (e.g. extracting default items, overlap checks).

Source

Thrown at compiler/rustc_middle/src/traits/specialization_graph.rs:45

pub struct Graph {
    /// All impls have a parent; the "root" impls have as their parent the `def_id`
    /// of the trait.
    pub parent: DefIdMap<DefId>,

    /// The "root" impls are found by looking up the trait's def_id.
    pub children: DefIdMap<Children>,
}

impl Graph {
    pub fn new() -> Graph {
        Graph { parent: Default::default(), children: Default::default() }
    }

    /// The parent of a given impl, which is the `DefId` of the trait when the
    /// impl is a "specialization root".
    #[track_caller]
    pub fn parent(&self, child: DefId) -> DefId {
        *self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {child:?}"))
    }
}

/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
/// purposes.
#[derive(Copy, Clone, PartialEq, Eq, Hash, StableHash, Debug, TyEncodable, TyDecodable)]
pub enum OverlapMode {
    /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
    Stable,
    /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
    WithNegative,
    /// Just check for negative impls, not for "where clause not implemented": used for testing.
    Strict,
}

impl OverlapMode {
    pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode {
        let with_negative_coherence = tcx.features().with_negative_coherence();

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Minimize the specialization graph to the smallest reproducing impl set and file an issue at https://github.com/rust-lang/rust with `-Ztoggle-features` / `--self-profile` output and the ICE backtrace.
  2. Try compiling with a stable toolchain (specialization is nightly-only) to confirm it is feature-gated machinery.
  3. Reduce the crate with `cargo bugoxide` / `creduce` on the `.rs` triggering coherence and bisect across nightly commits to find the regression.
  4. As a workaround, flatten the specialization (avoid a `default impl` chain that relies on parent traversal) or split the trait so no specialization parent lookup is required.

Example fix

// before: specialization chain forcing parent traversal
impl<T> default Trait for T { /* ... */ }
impl Trait for Vec<u8> { /* ... */ } // ICE: parent lookup for Vec<u8>

// after: avoid default impl, use direct blanket impl
impl<T> Trait for T { /* ... */ }
impl Trait for Vec<u8> { /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on specialization, verify the specialization graph is well-formed.
// Static check: reject overlapping impls unless `min_specialization` is active and sound.
fn assert_no_specialization_cycles(impls: &[&str]) -> Result<(), String> {
    // User-level guard: avoid the feature entirely on stable toolchains.
    if !cfg!(feature = "min_specialization") && impls.iter().any(|i| i.contains("default")) {
        return Err("specialization requires nightly + min_specialization; refusing to build graph".into());
    }
    Ok(())
}

Type guard

// Narrow a trait ref to a non-specialized concrete impl before resolving its parent.
fn is_concrete_specializable(t: &impl std::any::TypeInfo) -> bool {
    // Only allow types whose impl is the sole, non-default one.
    !t.is_trait_object() && t.implements_single_impl()
}

Prevention

When it happens

Trigger: Hit when the compiler calls `Graph::parent(child)` (specialization_graph.rs:44) for an impl `DefId` that was never inserted into the `parent` map during `Graph` construction — typically via specialization queries (`tcx.impls_in_trait`, default-item resolution, or overlap mode `WithNegative`/`Strict`).

Common situations: Using `min_specialization`/`specialization` with a complex impl hierarchy on nightly; adding a new blanket impl that interacts badly with existing specializations; regressions after a rustc upgrade that changes coherence ordering; cross-crate specialization where the child crate is compiled with a different feature set than the defining crate.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/dc7aceca8cf54ee1.json. Report an issue: GitHub.