rust-lang/rust · error · anyhow::Error

unparsed bytes: 0x{:02x?}

Error message

unparsed bytes: 0x{:02x?}

What it means

Raised by Parser::ensure_empty when, after consuming all expected fields of a coverage record, self.rest still contains trailing bytes. It is a structural integrity check: the parser's read sequence did not account for every byte in the input, meaning either an unknown extension field or a misparse occurred.

Source

Thrown at src/tools/coverage-dump/src/parser.rs:13

use anyhow::ensure;

pub(crate) struct Parser<'a> {
    rest: &'a [u8],
}

impl<'a> Parser<'a> {
    pub(crate) fn new(input: &'a [u8]) -> Self {
        Self { rest: input }
    }

    pub(crate) fn ensure_empty(self) -> anyhow::Result<()> {
        ensure!(self.rest.is_empty(), "unparsed bytes: 0x{:02x?}", self.rest);
        Ok(())
    }

    pub(crate) fn read_n_bytes(&mut self, n: usize) -> anyhow::Result<&'a [u8]> {
        ensure!(n <= self.rest.len());

        let (bytes, rest) = self.rest.split_at(n);
        self.rest = rest;
        Ok(bytes)
    }

    pub(crate) fn read_uleb128_u32(&mut self) -> anyhow::Result<u32> {
        self.read_uleb128_u64_and_convert()
    }

    pub(crate) fn read_uleb128_usize(&mut self) -> anyhow::Result<usize> {
        self.read_uleb128_u64_and_convert()
    }

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Rebuild coverage-dump from the same commit as the rustc that emitted the coverage data.
  2. Inspect the leftover bytes (0x..) for a recognizable LLVM coverage record tag to identify the new field.
  3. Check rust-lang/rust for recent changes to coverage mapping versioning (CoverageMappingVersion).
  4. Re-generate the coverage data with a toolchain matching coverage-dump's expected format version.

Example fix

// before: bail on any leftover bytes
ensure!(self.rest.is_empty(), "unparsed bytes: 0x{:02x?}", self.rest);

// after: tolerate unknown trailing bytes with a warning when forward-compat is desired
if !self.rest.is_empty() {
    tracing::warn!("unparsed {} trailing bytes: 0x{:02x?}", self.rest.len(), self.rest);
}
// (only do this if the format explicitly permits future extensions)
Defensive patterns

Strategy: validation

Validate before calling

// If you feed coverage-dump programmatically, verify the format version header
// matches what your coverage-dump build expects before parsing:
if coverage_format_version(&bytes) != SUPPORTED_VERSION {
    return Err(anyhow!("coverage format {} unsupported by this coverage-dump",
        coverage_format_version(&bytes)));
}

Type guard

null

Try / catch

match parser.ensure_empty() {
    Ok(()) => Ok(parsed),
    Err(e) => {
        tracing::warn!("parser left trailing bytes; coverage format may be newer: {e}");
        Ok(parsed) // only if forward-compat is acceptable for your use
    }
}

Prevention

When it happens

Trigger: Called at the end of parsing a coverage data structure (e.g. after reading all function records / counter expressions) when ensure_empty() is invoked on the Parser. Triggers when the LLVM coverage format version adds fields this coverage-dump does not know about, or when a preceding read_uleb128 under-read a length-prefixed region.

Common situations: Upgrading rustc/LLVM to a version that extended the coverage mapping format while coverage-dump is pinned to an older revision; manually crafted or fuzzed coverage inputs; a bug where a length field is read as u32 but the body is shorter, leaving leftover bytes.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/82740c326d9feb80. Report an issue: GitHub.