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
- Report to rust-lang/rust; this indicates an `AttrId`-bearing type was persisted cross-session, which is unsupported.
- 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.
- Audit the new `Decodable<CacheDecoder>` impl: grep the type's fields for `AttrId` / `Attribute` and remove or re-map them.
- 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
- Always `cargo clean` (or at least remove `target/<profile>/incremental`) after a rustup update.
- Do not cache `target/` keyed only on branch; include rustc version in the cache key.
- Prefer stable for shared build environments; nightly serialization formats churn.
- If reproducible on current nightly, file an ICE — AttrId format should be versioned.
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
- trying to decode `DefIndex` outside the context of a `DefId`
- Incremental cache file size overflowed u64.
- failed to lookup `SourceFile` in new context
- Bad hash {:?} (map {:?})
- Failed to convert DefPathHash {def_path_hash:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/feb8169af6d01b59.json.
Report an issue: GitHub.