{"record":{"id":"43dfa84444234864","repo":"jdx/mise","slug":"remote-cache-blob-pack-has-an-invalid-content-type","errorCode":null,"errorMessage":"remote cache blob pack has an invalid content type","messagePattern":"remote cache blob pack has an invalid content type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/lib.rs","lineNumber":640,"sourceCode":"                .send()\n                .await?;\n            if matches!(\n                response.status(),\n                StatusCode::NOT_FOUND\n                    | StatusCode::METHOD_NOT_ALLOWED\n                    | StatusCode::NOT_IMPLEMENTED\n            ) {\n                return Ok(None);\n            }\n            let response = response.error_for_status()?;\n            let media_type = response\n                .headers()\n                .get(CONTENT_TYPE)\n                .and_then(|value| value.to_str().ok())\n                .and_then(|value| value.split(';').next())\n                .map(str::trim);\n            if media_type != Some(BLOB_PACK_MEDIA_TYPE) {\n                bail!(\"remote cache blob pack has an invalid content type\");\n            }\n            Ok(Some(\n                decode_blob_pack(response, digests, staging_dir).await?,\n            ))\n        });\n        tokio::time::timeout(download_timeout, download)\n            .await\n            .map_err(|_| eyre!(\"remote cache blob pack download timed out for {url}\"))?\n    }\n\n    pub async fn get_action_result(\n        &self,\n        action: &CacheDigest,\n    ) -> Result<Option<RemoteActionResult>> {\n        let url = self.action_result_endpoint(action)?;\n        let result = retry_async(\"GET\", &url, self.retries, || async {\n            let response = self\n                .request(reqwest::Method::GET, url.clone(), ACTION_RESULT_MEDIA_TYPE)","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/lib.rs#L622-L658","documentation":"Thrown on a blob-pack download (crates/mise-cache-core/src/lib.rs:640): the response's Content-Type media type (taken before any ';' parameter, trimmed) is not exactly BLOB_PACK_MEDIA_TYPE = \"application/vnd.mise.cache-blob-pack.v1\". The check guards decode_blob_pack from consuming a body that is not actually the framed pack format.","triggerScenarios":"Calling the blob-pack GET path (the download closure around lib.rs:620-660) against a server that responds with e.g. application/octet-stream, application/json (an error body that still returned 200), text/plain, or the correct type with a typo. Also triggered by intermediaries that rewrite Content-Type.","commonSituations":"A reverse proxy defaulting the type on unmapped extensions; a server framework that does not set vendor media types; version skew where an older server predates the vendor type; an HTML error page from a gateway returned with 200 after error_for_status passed.","solutions":["Verify the server sets Content-Type: application/vnd.mise.cache-blob-pack.v1 on pack responses (parameters after ';' are tolerated, the media type itself is not)","Check for proxies/gateways stripping or defaulting the header; add an exception for the pack route","Confirm the pack feature is actually implemented server-side — if the endpoint is a stub returning JSON, disable blob packs client-side","Upgrade the server to a version matching the v1 pack media type"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// server-side, before returning a pack:\nassert_eq!(response.content_type(), \"application/vnd.mise.cache-blob-pack.v1\");\n// client-side preflight: check capabilities/features before requesting packs","typeGuard":null,"tryCatchPattern":"match client.get_blob_pack(&digests, &staging).await {\n    Err(e) if e.to_string().contains(\"invalid content type\") => {\n        client.disable_blob_packs();\n        fallback_per_blob(&client, &digests)\n    }\n    other => other?,\n}","preventionTips":["Set the exact vendor media type on pack routes; do not rely on framework defaults","Add proxy exceptions so Content-Type is preserved on cache routes","Treat any content-type failure as a signal to fall back to per-blob downloads, which work regardless"],"tags":["mise","cache","http","content-type","blob-pack","validation"],"backgroundTag":"unexpected-content-type","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}