jdx/mise · error

remote cache blob pack has invalid magic

Error message

remote cache blob pack has invalid magic

What it means

Thrown by decode_blob_pack (crates/mise-cache-core/src/lib.rs:899): every blob pack body must start with the 8-byte magic BLOB_PACK_MAGIC = b"MISEPK01" (lib.rs:46). The decoder reads exactly 8 bytes and bails if they differ — the response passed the Content-Type check (error 53) but the body is not actually the framed pack format.

Source

Thrown at crates/mise-cache-core/src/lib.rs:899

    let item_units = digests.len().div_ceil(BLOB_PACK_TIMEOUT_ITEMS_PER_UNIT);
    let item_units = u64::try_from(item_units).unwrap_or(u64::MAX);
    let multiplier = byte_units.max(item_units).max(1);
    base.saturating_mul(u32::try_from(multiplier).unwrap_or(u32::MAX))
}

async fn decode_blob_pack(
    response: reqwest::Response,
    requested: &[CacheDigest],
    staging_dir: &Path,
) -> Result<DownloadedBlobPack> {
    let metadata = BlobPackResponseMetadata::from_headers(response.headers())?;
    let requested = requested.iter().cloned().collect::<BTreeSet<_>>();
    let stream = response.bytes_stream().map_err(std::io::Error::other);
    let mut reader = tokio_util::io::StreamReader::new(stream);
    let mut magic = [0_u8; BLOB_PACK_MAGIC.len()];
    reader.read_exact(&mut magic).await?;
    if &magic != BLOB_PACK_MAGIC {
        bail!("remote cache blob pack has invalid magic");
    }

    let directory = tempfile::tempdir_in(staging_dir)?;
    let mut seen = BTreeSet::new();
    let mut blobs = Vec::new();
    let mut payload_bytes = 0_u64;
    let mut framed_bytes = BLOB_PACK_MAGIC.len() as u64;
    loop {
        let mut algorithm = [0_u8; 1];
        if reader.read(&mut algorithm).await? == 0 {
            break;
        }
        let (algorithm, mut hasher) = match algorithm[0] {
            1 => (
                "blake3",
                BlobPackHasher::Blake3(Box::new(blake3::Hasher::new())),
            ),
            2 => ("sha256", BlobPackHasher::Sha256(sha2::Sha256::new())),

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Align client and server versions — a magic mismatch almost always means a different container format generation
  2. Capture the first bytes of the offending response server-side to confirm what is actually being sent instead of the pack framing
  3. Verify no intermediary (proxy, WAF, gateway) is substituting the response body on the pack route
  4. If you operate the server, emit the MISEPK01 header bytes exactly before the record stream
Defensive patterns

Strategy: fallback

Validate before calling

// cheap preflight if you control the server: expose a format version in capabilities
// and refuse to request packs when it differs from the client's pack generation

Try / catch

match client.get_blob_pack(&digests, &staging).await {
    Err(e) if e.to_string().contains("invalid magic") => {
        client.disable_blob_packs(); // format generation mismatch — packs unusable
        fallback_per_blob(&client, &digests)
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling the blob-pack download path where the body starts with something other than MISEPK01 — e.g. the server sends uncompressed JSON or raw concatenated blobs, sends a newer pack format (MISEPK02) after a protocol bump, or a proxy/error page replaced the body while preserving the 200 status and vendor Content-Type.

Common situations: Version skew: server writes a newer pack container than the client decodes; partially implemented server that sets headers but streams a different serialization; intermediaries substituting bodies; truncated responses where the first 8 bytes come from an error payload.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/825ce067f8385d41. Report an issue: GitHub.