rust-lang/rust · critical
Invalid tag for ClearCrossCrate: {tag:?}
Error message
Invalid tag for ClearCrossCrate: {tag:?} What it means
Panic in `ClearCrossCrate<T>::decode` when decoding an incremental-compilation / cross-crate query result: the discriminant byte read from the on-disk cache is neither TAG_CLEAR_CROSS_CRATE_CLEAR (0) nor TAG_CLEAR_CROSS_CRATE_SET (1). rustc_middle throws it because the encoded stream's tag enum is closed and an unknown byte can only mean a corrupted cache or a decoder/encoder version mismatch.
Source
Thrown at compiler/rustc_middle/src/mir/mod.rs:831
}
}
}
impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
#[inline]
fn decode(d: &mut D) -> ClearCrossCrate<T> {
if D::CLEAR_CROSS_CRATE {
return ClearCrossCrate::Clear;
}
let discr = u8::decode(d);
match discr {
TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear,
TAG_CLEAR_CROSS_CRATE_SET => {
let val = T::decode(d);
ClearCrossCrate::Set(val)
}
tag => panic!("Invalid tag for ClearCrossCrate: {tag:?}"),
}
}
}
/// Grouped information about the source code origin of a MIR entity.
/// Intended to be inspected by diagnostics and debuginfo.
/// Most passes can work with it as a whole, within a single function.
// The unofficial Cranelift backend, at least as of #65828, needs `SourceInfo` to implement `Eq` and
// `Hash`. Please ping @bjorn3 if removing them.
#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, StableHash)]
pub struct SourceInfo {
/// The source span for the AST pertaining to this MIR entity.
pub span: Span,
/// The source scope, keeping track of which bindings can be
/// seen by debuginfo, active lint levels, etc.
pub scope: SourceScope,
}View on GitHub (pinned to 22057b88b0)
Solutions
- Delete the incremental cache and build artifacts: `cargo clean` (or remove `target/debug/incremental`), then rebuild.
- Ensure every crate in the dependency graph is compiled by the same rustc commit/nightly; re-compile dependencies from source rather than mixing rmeta from different toolchains.
- If using a custom rustc driver or backend that touches `ClearCrossCrate` encoding, verify it only ever writes TAG_CLEAR_CROSS_CRATE_CLEAR or TAG_CLEAR_CROSS_CRATE_SET and bump the cache schema/version when the encoding changes.
- Report a bug to rustc with the panic backtrace and the exact rustc commit if the corruption recurs on a clean cache with a single consistent toolchain.
Example fix
# before (stale cache corrupts decode) cargo build # thread 'rustc' panicked at compiler/rustc_middle/src/mir/mod.rs:831: Invalid tag for ClearCrossCrate: ... # after cargo clean && cargo build
Defensive patterns
Strategy: fallback
Validate before calling
// No pre-call validation is possible: the discriminant tag is an opaque
// byte inside the already-encoded rmeta/incremental stream.
// The only reliable recovery is to discard the corrupted artifact.
fn artifact_is_likely_stale(crate_stamp: std::time::SystemTime, src_stamp: std::time::SystemTime) -> bool {
crate_stamp < src_stamp // cached object predates its source
} Try / catch
// ClearCrossCrate::decode panics on an unknown tag (stream corruption).
// Wrap the decode and, on panic, fall back to a clean rebuild.
use std::panic::{catch_unwind, AssertUnwindSafe};
let decoded = catch_unwind(AssertUnwindSafe(|| {
// <T as Decodable>::decode(&mut decoder_for_clearcrosscrate)
decode_clearcrosscrate::<T>(&mut d)
}));
match decoded {
Ok(value) => value,
Err(_payload) => {
// incremental / rmeta stream was corrupt -> purge and rebuild
let _ = std::fs::remove_dir_all("target/debug/incremental");
let _ = std::fs::remove_file(offending_rmeta_path);
// re-run the build without --incremental for this crate
panic_not_a_user_error_but_rebuild_initiated();
}
} Prevention
- Treat this panic as data corruption: it fires only when decoding cross-crate MIR cached by a prior, possibly-incompatible compiler build.
- Never mix artifacts between rustc versions or between incremental sessions; run `cargo clean` (or remove target/debug/incremental) after a toolchain update.
- Avoid aborting a build midway (kill -9, OOM, power loss) which can leave half-written rmeta/incremental blobs that decode to invalid tags.
- If you persist or transfer rmeta/incremental caches, checksum them; reject and regenerate on mismatch instead of feeding bad bytes to the decoder.
When it happens
Trigger: Triggered when rustc deserializes a `ClearCrossCrate<T>` from the incremental/incremental-compilation cache or an rmeta/crate-metadata stream whose first byte after the CLEAR_CROSS_CRATE gating check is not 0 or 1. Reproducible by manually truncating or patching a cached object, or by loading an rmeta written by a different compiler build whose encoder changed the tag layout.
Common situations: Stale or partially-written incremental cache after a SIGKILL/OOM or disk-full during a prior build; switching between compiler nightlies without clearing `target/`; mismatched rustc driver / custom backend that re-encodes `ClearCrossCrate` with a non-canonical tag; rlib/rmeta produced by an experimental toolchain being consumed by another.
Related errors
- counting sort fills every slot of a kind's range
- Could not find work-product for CGU `{}`
- Incremental cache file size overflowed u64.
- failed to lookup `SourceFile` in new context
- Bad hash {:?} (map {:?})
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/31bce38ae2426a58.json.
Report an issue: GitHub.