rust-lang/rust · critical

local id should be u32, found {local_id:?}

Error message

local id should be u32, found {local_id:?}

What it means

In `HirId::try_recover_key` (dep_node_key.rs:189), while forcing an HirId-keyed dep node during incremental compilation, the compiler splits the stored Fingerprint and treats one half as the ItemLocalId. That half must fit in u32; if it does not, conversion fails with this panic, signalling the fingerprint is not a valid HirId encoding.

Source

Thrown at compiler/rustc_middle/src/dep_graph/dep_node_key.rs:189

        let HirId { owner, local_id } = *self;
        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
        Fingerprint::new(
            // `owner` is local, so is completely defined by the local hash
            def_path_hash.local_hash(),
            local_id.as_u32() as u64,
        )
    }

    #[inline(always)]
    fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
            let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split();
            let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
            let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
            let local_id = local_id
                .as_u64()
                .try_into()
                .unwrap_or_else(|_| panic!("local id should be u32, found {local_id:?}"));
            Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
        } else {
            None
        }
    }
}

impl<'tcx> DepNodeKey<'tcx> for ModId {
    #[inline(always)]
    fn key_fingerprint_style() -> KeyFingerprintStyle {
        KeyFingerprintStyle::DefPathHash
    }

    #[inline(always)]
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        self.to_def_id().to_fingerprint(tcx)
    }

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Delete the incremental cache (`rm -rf target/<profile>/incremental`) or `cargo clean` and rebuild.
  2. Confirm the same toolchain is used for the whole build so the previous dep graph is decoder-compatible.
  3. If it reproduces cleanly, capture a minimal repro and file a rustc issue against the HirId fingerprint/dep-node recovery path.
Defensive patterns

Strategy: type-guard

Validate before calling

// DepNode keys may carry a local id that must fit in u32.
fn local_id_as_u32(local_id: &LocalIdRef) -> Result<u32, String> {
    match local_id {
        LocalIdRef::U32(v) => Ok(*v),
        other => Err(format!("local id should be u32, found {:?}", other)),
    }
}

Type guard

fn local_id_is_u32(local_id: &LocalIdRef) -> bool {
    matches!(local_id, LocalIdRef::U32(_))
}

Prevention

When it happens

Trigger: A dep node whose fingerprint's local_id half exceeds u32::MAX is being decoded as an HirId — caused by a corrupted/invalid serialized dep graph, a fingerprint written by an incompatible compiler, or an internal hashing bug that stored a non-HirId fingerprint under a HirId-kind dep node.

Common situations: Corrupted incremental cache (interrupted write, disk issue, copied across machines/toolchains), toolchain mismatch leaving an incompatible previous dep graph, or an internal compiler bug in HirId fingerprinting.

Related errors


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