jdx/mise · error

attestation requests must not have a streaming body

Error message

attestation requests must not have a streaming body

What it means

The sigstore attestation client retries HTTP requests, which requires cloning the reqwest::RequestBuilder between attempts. If the request body is streaming (non-replayable), try_clone returns None and this panic fires. It is an internal invariant: attestation requests must always use in-memory (cloneable) bodies.

Source

Thrown at crates/mise-sigstore/src/lib.rs:439

        reqwest::Url::parse_with_params(&url, query_params)
            .map_err(|e| AttestationError::Api(format!("Invalid GitHub attestations URL: {e}")))
    }

    /// Send a request and read its body, retrying transient failures (5xx, 429,
    /// timeouts, connection errors, and mid-body-read errors) with exponential
    /// backoff. A `429`'s `Retry-After` header is honored in preference to the
    /// computed backoff. The body is buffered here so a transient failure during
    /// the body read is retried too, rather than escaping the retry boundary.
    ///
    /// The request must have no streaming body so it can be cloned per attempt —
    /// true for all GET calls here. Non-transient responses (incl. 4xx like 404)
    /// are returned as-is for the caller to interpret.
    async fn send_with_retry(&self, request: reqwest::RequestBuilder) -> Result<HttpResponse> {
        let mut attempt = 1;
        loop {
            let req = request
                .try_clone()
                .expect("attestation requests must not have a streaming body");
            let last = attempt >= self.max_attempts;

            // A labeled block so the `reqwest::Response` is dropped before the
            // backoff sleep — holding it would pin its body/connection for the
            // whole delay. Each attempt either returns, errors out, or breaks
            // with the delay to wait before the next attempt.
            let delay = 'attempt: {
                match req.send().await {
                    Ok(response) => {
                        let status = response.status();
                        if !last && is_retryable_status(status) {
                            break 'attempt retry_after_delay(response.headers())
                                .unwrap_or_else(|| backoff_delay(self.backoff_base, attempt));
                        }
                        let headers = response.headers().clone();
                        match response.bytes().await {
                            Ok(body) => {
                                return Ok(HttpResponse {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. This is a mise-internal bug: report it at github.com/jdx/mise/issues with the command and version
  2. As a workaround, keep the request payload small/in-memory (it should be by design)
  3. Pin to an earlier mise version if a recent release introduced the regression

Example fix

// before
let req = client.post(url).body(some_stream);
// after
let req = client.post(url).body(bytes.to_vec()); // cloneable fixed body
Defensive patterns

Strategy: try-catch

Type guard

fn body_is_cloneable(req: &reqwest::RequestBuilder) -> bool { req.try_clone().is_some() }

Try / catch

// panic is by design; guard by asserting cloneability before building the request
assert!(request.try_clone().is_some(), "attestation body must be in-memory");

Prevention

When it happens

Trigger: fetch_attestations or fetch_bundle_url building a request whose body is a stream (e.g. passing a reader/stream body instead of a fixed byte buffer), then send_with_retry calling try_clone.

Common situations: Code changes that swap a JSON/byte body for a streaming upload; large attestation payloads fed via stream; a library bug rather than user misconfiguration.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/62a9caa5f45d6dcb. Report an issue: GitHub.