Pumpkin-MC/Pumpkin · error · HttpError
Failed to read HTTP response body
Error message
Failed to read HTTP response body: {0} What it means
HttpError::BodyRead from pumpkin-plugin-utils' HttpClient. It means an HTTP request to a marketplace API succeeded at the transport level, but the response body could not be read into a string/buffer (connection dropped mid-body, timeout while streaming, decompression failure, etc.). reqwest's `.text()`/`.bytes()` failed and the underlying error string is embedded via {0}.
Solutions
- Retry the request once; BodyRead is often transient (dropped connection).
- Increase or verify the reqwest client's read/total timeout in HttpClient configuration.
- Check network/proxy stability (curl the marketplace endpoint to confirm full body arrives).
- Inspect the embedded reqwest error ({0}) for 'timed out' vs 'connection reset' to target the cause.
- Pin/verify TLS and compression features match the server (disable optional gzip feature if decompression errors persist).
Example fix
// before
let body = resp.text()?; // surfaces BodyRead on failure
// after
let body = match resp.text() {
Ok(b) => b,
Err(e) => { tracing::warn!("body read failed, retrying: {e}"); resp2.text()? }
}; Defensive patterns
Strategy: retry
Validate before calling
// Best-effort pre-check that the endpoint is reachable before issuing the real call
if let Err(e) = std::net::TcpStream::connect_timeout(
&marketplace_addr, std::time::Duration::from_secs(5)) {
tracing::warn!("marketplace unreachable, skipping call: {e}");
return Ok(None);
} Type guard
fn is_body_read(e: &HttpError) -> bool {
matches!(e, HttpError::BodyRead(_))
} Try / catch
match client.get(url).send().and_then(|r| r.text()) {
Ok(body) => parse(body),
Err(HttpError::BodyRead(e)) => {
tracing::warn!("transient body read failure: {e}");
backoff_retry(|| fetch(), 3)
}
Err(e) => Err(e.into()),
} Prevention
- Set a generous read_timeout on the reqwest blocking client.
- Retry idempotent GETs with exponential backoff.
- Avoid proxies/interceptors that truncate responses.
- Monitor the embedded error string to distinguish timeouts vs resets.
When it happens
Trigger: Calling any HttpClient method (e.g. marketplace license or update queries) where reqwest::blocking::Response::text()/bytes() returns Err: server closes connection before sending full body, read timeout elapses mid-download, chunked encoding interrupted, or decompression (gzip/brotli) of the body fails.
Common situations: Unstable network or proxy between the plugin host and the marketplace; marketplace server crashes mid-response; overly short reqwest read_timeout; intercepting proxies/antivirus truncating responses; very large bodies with socket resets.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Marketplace HTTP error
- HTTP request failed
- Failed to query update API
- EOF, Tried to read but No bytes left to consume
- incomplete
AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09).
Data as JSON: /api/errors/0f83e5378ed8225a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/pumpkin-plugin-utils/src/http.rs:15
//! HTTP client helpers for online license checks and marketplace queries.
use thiserror::Error;
/// HTTP request errors.
#[derive(Debug, Error)]
pub enum HttpError {
/// Network or connection error.
#[error("HTTP request failed: {0}")]
RequestFailed(String),
/// Response status code was not successful (2xx).
#[error("HTTP response returned error status {0}: {1}")]
BadStatus(u16, String),
/// Error reading response body.
#[error("Failed to read HTTP response body: {0}")]
BodyRead(String),
}
/// Helper client for querying Pumpkin marketplace REST APIs.
pub struct HttpClient {
client: reqwest::blocking::Client,
}
impl Default for HttpClient {
fn default() -> Self {
Self::new("Pumpkin-Plugin-Utils/0.1.0")
}
}
impl HttpClient {
/// Creates a new HTTP client with the specified User-Agent header.
#[must_use]
pub fn new(user_agent: &str) -> Self {View on GitHub (pinned to 8d4639e25a)