jdx/mise · error

remote cache blob pack has an invalid content type

Error message

remote cache blob pack has an invalid content type

What it means

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.

Source

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

                .send()
                .await?;
            if matches!(
                response.status(),
                StatusCode::NOT_FOUND
                    | StatusCode::METHOD_NOT_ALLOWED
                    | StatusCode::NOT_IMPLEMENTED
            ) {
                return Ok(None);
            }
            let response = response.error_for_status()?;
            let media_type = response
                .headers()
                .get(CONTENT_TYPE)
                .and_then(|value| value.to_str().ok())
                .and_then(|value| value.split(';').next())
                .map(str::trim);
            if media_type != Some(BLOB_PACK_MEDIA_TYPE) {
                bail!("remote cache blob pack has an invalid content type");
            }
            Ok(Some(
                decode_blob_pack(response, digests, staging_dir).await?,
            ))
        });
        tokio::time::timeout(download_timeout, download)
            .await
            .map_err(|_| eyre!("remote cache blob pack download timed out for {url}"))?
    }

    pub async fn get_action_result(
        &self,
        action: &CacheDigest,
    ) -> Result<Option<RemoteActionResult>> {
        let url = self.action_result_endpoint(action)?;
        let result = retry_async("GET", &url, self.retries, || async {
            let response = self
                .request(reqwest::Method::GET, url.clone(), ACTION_RESULT_MEDIA_TYPE)

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. 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)
  2. Check for proxies/gateways stripping or defaulting the header; add an exception for the pack route
  3. Confirm the pack feature is actually implemented server-side — if the endpoint is a stub returning JSON, disable blob packs client-side
  4. Upgrade the server to a version matching the v1 pack media type
Defensive patterns

Strategy: validation

Validate before calling

// server-side, before returning a pack:
assert_eq!(response.content_type(), "application/vnd.mise.cache-blob-pack.v1");
// client-side preflight: check capabilities/features before requesting packs

Try / catch

match client.get_blob_pack(&digests, &staging).await {
    Err(e) if e.to_string().contains("invalid content type") => {
        client.disable_blob_packs();
        fallback_per_blob(&client, &digests)
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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