rust-lang/rust · critical
Bad hash {:?} (map {:?})
Error message
Bad hash {:?} (map {:?}) What it means
`CacheDecoder::decode_expn_id` (on_disk_cache.rs:580) looks up the byte position of an `ExpnData` record by its `ExpnHash` in the `expn_data` map persisted in the cache footer. A miss (`.unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, self.expn_data))`) means the expansion's hygiene hash stored inside an encoded query result has no corresponding entry in the local crate's `expn_data` table.
Source
Thrown at compiler/rustc_middle/src/query/on_disk_cache.rs:580
fn decode_expn_id(&mut self) -> ExpnId {
let hash = ExpnHash::decode(self);
if hash.is_root() {
return ExpnId::root();
}
if let Some(expn_id) = ExpnId::from_hash(hash) {
return expn_id;
}
let krate = self.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id());
let expn_id = if krate == LOCAL_CRATE {
// We look up the position of the associated `ExpnData` and decode it.
let pos = self
.expn_data
.get(&hash)
.unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, self.expn_data));
let data: ExpnData =
self.with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA));
let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash);
#[cfg(debug_assertions)]
{
use rustc_data_structures::stable_hash::{StableHash, StableHasher};
let local_hash = self.tcx.with_stable_hashing_context(|mut hcx| {
let mut hasher = StableHasher::new();
expn_id.expn_data().stable_hash(&mut hcx, &mut hasher);
hasher.finish()
});
debug_assert_eq!(hash.local_hash(), local_hash);
}
expn_id
} else {View on GitHub (pinned to 22057b88b0)
Solutions
- Delete `target/<triple>/incremental/` (and `target/debug/incremental/`) and rebuild.
- If you edit a proc-macro or macro_rules crate, run `cargo clean -p <macro-crate>` before rebuilding dependents.
- Run `cargo clean && cargo build` to rule out cascading stale caches.
- Disable incremental compilation for the affected workflow: `CARGO_INCREMENTAL=0`.
- Ensure your CI cache key includes the full source hash of proc-macro crates and the toolchain version.
- Report to rust-lang/rust if it reproduces after a clean build, with `rustc -vV` and the macro setup.
Example fix
# before
$ vim my-proc-macro/src/lib.rs # change macro hygiene
$ cargo build # panic: Bad hash ExpnHash{...} (map {...})
# after
$ cargo clean -p my-proc-macro
$ cargo build # dependents rebuild with fresh hygiene table Defensive patterns
Strategy: validation
Validate before calling
// Verify the incremental cache file's recorded hash matches its bytes before reuse,
// to catch corruption from disk errors, partial writes, or cross-FS copies.
use std::fs;
use std::path::Path;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn cache_intact(path: &Path, expected_hash: u64) -> bool {
let Ok(bytes) = fs::read(path) else { return false };
let mut h = DefaultHasher::new();
bytes.hash(&mut h);
h.finish() == expected_hash
} Prevention
- Do not copy `target/` between machines or filesystems — incremental blobs are not portable.
- Ensure builds finish before syncing/snapshotting the workspace (partial writes corrupt the hash map).
- Validate hardware: silent disk corruption (bit rot) commonly surfaces as hash mismatches.
- Treat any `Bad hash` panic as cache corruption: `cargo clean` and rebuild.
When it happens
Trigger: Reached when decoding a `Span`/`ExpnId` from the incremental cache and `ExpnId::from_hash(hash)` returns `None` for a `LOCAL_CRATE` hash, then the footer's `expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>` also lacks it. Indicates the cache and the live hygiene context disagree on which macro expansions existed in the local crate.
Common situations: Typical after a proc-macro or declarative-macro definition changed between sessions but the incremental cache wasn't invalidated (e.g. macro_rules in a dependency edited without bumping its version, a proc-macro crate rebuilt without `cargo clean`, an editor/IDE that rewrites files mid-build, or a CI layer that restored a stale incremental dir).
Related errors
- Incremental cache file size overflowed u64.
- failed to lookup `SourceFile` in new context
- Failed to convert DefPathHash {def_path_hash:?}
- counting sort fills every slot of a kind's range
- Invalid tag for ClearCrossCrate: {tag:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/a1d6d207a4ad862e.json.
Report an issue: GitHub.