headroomlabs-ai/headroom · warning

metrics response build error: {e}

Error message

metrics response build error: {e}

What it means

Building the 200 OK /metrics Response object failed after successful encoding (setting status/header/body on http::Response). This is a can't-happen branch — the response is fully static except for the encoded buffer — so it exists only as an unwrap_or_else guard, returning 500 with this message.

Source

Thrown at crates/headroom-proxy/src/observability/prometheus.rs:286

    if let Err(e) = encoder.encode(&metric_families, &mut buffer) {
        tracing::error!(
            event = "metrics_encode_failed",
            error = %e,
            "failed to encode Prometheus metrics scrape"
        );
        return Response::builder()
            .status(StatusCode::INTERNAL_SERVER_ERROR)
            .body(Body::from(format!("metrics encode error: {e}")))
            .expect("static error response");
    }
    Response::builder()
        .status(StatusCode::OK)
        .header(header::CONTENT_TYPE, encoder.format_type())
        .body(Body::from(buffer))
        .unwrap_or_else(|e| {
            Response::builder()
                .status(StatusCode::INTERNAL_SERVER_ERROR)
                .body(Body::from(format!("metrics response build error: {e}")))
                .expect("static error response")
        })
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Helper: render the registry to a String for assertions.
    fn scrape() -> String {
        let mf = registry().gather();
        let encoder = TextEncoder::new();
        let mut buf = Vec::new();
        encoder.encode(&mf, &mut buf).expect("encode");
        String::from_utf8(buf).expect("utf8")
    }

    #[test]

View on GitHub (pinned to 322425c43b)

Solutions

  1. If it fires, capture the metrics_response_build_error body — it embeds the underlying http::Error.
  2. Check the prometheus crate version's format_type() string (should be 'text/plain; version=0.0.4' or similar) against http::HeaderValue rules.
  3. Downgrade/pin the prometheus crate to a version whose format string is known-good.
Defensive patterns

Strategy: try-catch

Prevention

When it happens

Trigger: http::Response::builder rejecting the header value (encoder.format_type() returning something http::HeaderValue refuses) — effectively only possible via a corrupted/changed encoder format string; otherwise unreachable.

Common situations: A prometheus-crate version change to format_type() output that no longer parses as a header value; memory corruption; in practice this should never fire.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/5727eadbb1aa740d. Report an issue: GitHub.