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
- Align client and server versions — a magic mismatch almost always means a different container format generation
- Capture the first bytes of the offending response server-side to confirm what is actually being sent instead of the pack framing
- Verify no intermediary (proxy, WAF, gateway) is substituting the response body on the pack route
- 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
- Bump PROTOCOL_VERSION (and pack magic) together so old clients fail the capability check instead of the magic check
- Never serve a non-pack body on the pack route, even for errors — use proper status codes
- Fall back to per-blob downloads on any pack decode failure; they are independently verified
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
- remote cache blob pack has an invalid digest algorithm
- remote cache blob pack content length metadata mismatch: exp
- remote cache blob pack blob count metadata mismatch: expecte
- remote cache blob pack payload byte metadata mismatch: expec
- remote cache blob packs require a positive max_pack_bytes li
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/825ce067f8385d41.
Report an issue: GitHub.