{"id":"dc7aceca8cf54ee1","repo":"rust-lang/rust","slug":"failed-to-get-parent-for-child","errorCode":null,"errorMessage":"Failed to get parent for {child:?}","messagePattern":"Failed to get parent for (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_middle/src/traits/specialization_graph.rs","lineNumber":45,"sourceCode":"pub struct Graph {\n    /// All impls have a parent; the \"root\" impls have as their parent the `def_id`\n    /// of the trait.\n    pub parent: DefIdMap<DefId>,\n\n    /// The \"root\" impls are found by looking up the trait's def_id.\n    pub children: DefIdMap<Children>,\n}\n\nimpl Graph {\n    pub fn new() -> Graph {\n        Graph { parent: Default::default(), children: Default::default() }\n    }\n\n    /// The parent of a given impl, which is the `DefId` of the trait when the\n    /// impl is a \"specialization root\".\n    #[track_caller]\n    pub fn parent(&self, child: DefId) -> DefId {\n        *self.parent.get(&child).unwrap_or_else(|| panic!(\"Failed to get parent for {child:?}\"))\n    }\n}\n\n/// What kind of overlap check are we doing -- this exists just for testing and feature-gating\n/// purposes.\n#[derive(Copy, Clone, PartialEq, Eq, Hash, StableHash, Debug, TyEncodable, TyDecodable)]\npub enum OverlapMode {\n    /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)\n    Stable,\n    /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.\n    WithNegative,\n    /// Just check for negative impls, not for \"where clause not implemented\": used for testing.\n    Strict,\n}\n\nimpl OverlapMode {\n    pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode {\n        let with_negative_coherence = tcx.features().with_negative_coherence();","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_middle/src/traits/specialization_graph.rs#L27-L63","documentation":"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).","triggerScenarios":"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`).","commonSituations":"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.","solutions":["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.","Try compiling with a stable toolchain (specialization is nightly-only) to confirm it is feature-gated machinery.","Reduce the crate with `cargo bugoxide` / `creduce` on the `.rs` triggering coherence and bisect across nightly commits to find the regression.","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."],"exampleFix":"// before: specialization chain forcing parent traversal\nimpl<T> default Trait for T { /* ... */ }\nimpl Trait for Vec<u8> { /* ... */ } // ICE: parent lookup for Vec<u8>\n\n// after: avoid default impl, use direct blanket impl\nimpl<T> Trait for T { /* ... */ }\nimpl Trait for Vec<u8> { /* ... */ }","handlingStrategy":"validation","validationCode":"// Before relying on specialization, verify the specialization graph is well-formed.\n// Static check: reject overlapping impls unless `min_specialization` is active and sound.\nfn assert_no_specialization_cycles(impls: &[&str]) -> Result<(), String> {\n    // User-level guard: avoid the feature entirely on stable toolchains.\n    if !cfg!(feature = \"min_specialization\") && impls.iter().any(|i| i.contains(\"default\")) {\n        return Err(\"specialization requires nightly + min_specialization; refusing to build graph\".into());\n    }\n    Ok(())\n}","typeGuard":"// Narrow a trait ref to a non-specialized concrete impl before resolving its parent.\nfn is_concrete_specializable(t: &impl std::any::TypeInfo) -> bool {\n    // Only allow types whose impl is the sole, non-default one.\n    !t.is_trait_object() && t.implements_single_impl()\n}","tryCatchPattern":null,"preventionTips":["Avoid `min_specialization` on nightly unless you control every impl in the graph; prefer marker-struct based specialization which stays sound on stable.","Pin a known-good stable rustc for CI; nightly specialization_graph churn is the leading trigger for parent-lookup ICEs.","Never query a specialization parent at runtime from proc-macro/tool code without first confirming the impl is reachable in the current crate graph.","Run `cargo +stable check` as a gate; if stable accepts the impl set but nightly ICEs, file the bug rather than shipping."],"tags":["rustc-ice","specialization","coherence","nightly","compiler-internal"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}