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

  1. Delete `target/<triple>/incremental/` (and `target/debug/incremental/`) and rebuild.
  2. If you edit a proc-macro or macro_rules crate, run `cargo clean -p <macro-crate>` before rebuilding dependents.
  3. Run `cargo clean && cargo build` to rule out cascading stale caches.
  4. Disable incremental compilation for the affected workflow: `CARGO_INCREMENTAL=0`.
  5. Ensure your CI cache key includes the full source hash of proc-macro crates and the toolchain version.
  6. 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

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


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