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
- Delete the incremental cache (`rm -rf target/<profile>/incremental`) or `cargo clean` and rebuild.
- Confirm the same toolchain is used for the whole build so the previous dep graph is decoder-compatible.
- 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
- Treat DepNode keys as opaque; do not reinterpret/stuff non-u32 values into the local-id slot.
- When serializing dep-graph data, encode type tags so a widened local-id representation round-trips safely.
- If you write a custom dep-node decoder, assert the variant before extracting the integer.
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
- Invalid DepKind {u}
- Cannot summarize when dependencies are not recorded.
- try_mark_previous_green() - forcing failed to set a color
- Query label {label} does not exist
- forbidden edge {:?} -> {:?} created
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/e7f33eb7f0eb9eca.json.
Report an issue: GitHub.