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

  1. Delete the incremental cache and build artifacts: `cargo clean` (or remove `target/debug/incremental`), then rebuild.
  2. 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.
  3. 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.
  4. 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

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


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