rust-lang/rust · critical

cannot decode `AttrId` with `CacheDecoder`

Error message

cannot decode `AttrId` with `CacheDecoder`

What it means

`CacheDecoder::decode_attr_id` (on_disk_cache.rs:667) is intentionally a hard `panic!("cannot decode AttrId with CacheDecoder")`. `AttrId` is an interner key whose numeric value is not stable across compilation sessions, so it cannot be safely restored from the incremental on-disk cache. The decoder refuses rather than silently returning a wrong attribute. Hitting it means some type that (directly or transitively) contains an `AttrId` was encoded into a cross-session query result, which is a compiler bug.

Source

Thrown at compiler/rustc_middle/src/query/on_disk_cache.rs:667

    // compilation sessions. We use the `DefPathHash`, which is stable across
    // sessions, to map the old `DefId` to the new one.
    fn decode_def_id(&mut self) -> DefId {
        // Load the `DefPathHash` which is was we encoded the `DefId` as.
        let def_path_hash = DefPathHash::decode(self);

        // Using the `DefPathHash`, we can lookup the new `DefId`.
        // Subtle: We only encode a `DefId` as part of a query result.
        // If we get to this point, then all of the query inputs were green,
        // which means that the definition with this hash is guaranteed to
        // still exist in the current compilation session.
        match self.tcx.def_path_hash_to_def_id(def_path_hash) {
            Some(r) => r,
            None => panic!("Failed to convert DefPathHash {def_path_hash:?}"),
        }
    }

    fn decode_attr_id(&mut self) -> rustc_span::AttrId {
        panic!("cannot decode `AttrId` with `CacheDecoder`");
    }
}

impl<'a, 'tcx> BlobDecoder for CacheDecoder<'a, 'tcx> {
    fn decode_symbol(&mut self) -> Symbol {
        self.decode_symbol_or_byte_symbol(
            Symbol::new,
            |this| Symbol::intern(this.read_str()),
            |opaque| Symbol::intern(opaque.read_str()),
        )
    }

    fn decode_byte_symbol(&mut self) -> ByteSymbol {
        self.decode_symbol_or_byte_symbol(
            ByteSymbol::new,
            |this| ByteSymbol::intern(this.read_byte_str()),
            |opaque| ByteSymbol::intern(opaque.read_byte_str()),
        )

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Report to rust-lang/rust; this indicates an `AttrId`-bearing type was persisted cross-session, which is unsupported.
  2. If you added the offending type in-tree, exclude it from cross-session caching or convert the `AttrId` to a stable form (e.g. re-encode the attribute's logical content, not the interner key) before persisting.
  3. Audit the new `Decodable<CacheDecoder>` impl: grep the type's fields for `AttrId` / `Attribute` and remove or re-map them.
  4. Re-run `x.py test compiler/rustc_middle` after the change to confirm no query result re-introduces the path.

Example fix

// before — derive blindly persists an unstable interner key
#[derive(Encodable, Decodable)]
struct PersistedItem {
    attrs: Vec<rustc_ast::AttrId>, // panics on decode
    body: BodyId,
}

// after — store a stable representation instead
#[derive(Encodable, Decodable)]
struct PersistedItem {
    attr_kinds: Vec<AttrKind>, // logical, session-stable content
    body: BodyId,
}
Defensive patterns

Strategy: fallback

Try / catch

// AttrId decoding with CacheDecoder fails when the cache predates a serialization
// format change (typical after a rustc update). No source guard exists.
use std::process::Command;
fn build_after_toolchain_bump(dir: &str) -> std::io::Result<std::process::ExitStatus> {
    // Wipe artifacts encoded by the previous rustc before rebuilding.
    let _ = Command::new("cargo").args(["clean"]).current_dir(dir).status();
    Command::new("cargo").arg("build").current_dir(dir).status()
}

Prevention

When it happens

Trigger: Reached when `Decodable<CacheDecoder>` is derived or hand-written for a struct/enum that contains an `AttrId` (or a field whose type contains one), and a query returning that type gets persisted to disk via the incremental cache. The derive blindly generates a call to `decode_attr_id`, which always panics.

Common situations: Seen by rustc contributors extending the query system or adding a new persisted type that inadvertently includes HIR attribute data, or by tooling that derives `Decodable` for a wrapper around an `AttrId`-bearing type and persists it. End users of stable rustc do not trigger this; if a stable build hits it, the compiler itself regressed.

Related errors


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