influxdata/influxdb · error · Error
io error
Error message
io error: {0} What it means
This is the IO variant of influxdb3_client::Error, produced via #[from] std::io::Error. It wraps any underlying I/O failure (socket read/write, connection reset, file I/O) that occurs while the HTTP client performs a request. The original std::io::Error is preserved as the error source.
Solutions
- Check the error source (std::io::Error) for the root cause (e.g. 'connection reset by peer', 'broken pipe').
- Retry the request — transient IO failures on pooled connections are common; use a retry with backoff.
- Verify the InfluxDB 3 server URL, port, and that the server is running and reachable (curl the health endpoint).
- Disable/inspect proxies or TLS interception; ensure firewall rules allow the connection.
- Update reqwest/hyper and the client to pick up connection-pool and keep-alive fixes.
Example fix
// before: unwrap and crash on IO errors
let resp = client.api_v3_query_sql(...).await.unwrap();
// after: handle IO variant with a retry
match client.api_v3_query_sql(...).await {
Err(e) if matches!(e, influxdb3_client::Error::IO(_)) => {
tokio::time::sleep(Duration::from_secs(1)).await;
retry_query().await?;
}
other => other?,
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight connectivity check before issuing queries/writes
async fn server_reachable(url: &str) -> bool {
reqwest::get(format!("{url}/health")).await
.map(|r| r.status().is_success())
.unwrap_or(false)
} Type guard
fn is_io_error(e: &influxdb3_client::Error) -> bool {
matches!(e, influxdb3_client::Error::IO(_))
} Try / catch
match client.api_v3_query_sql(...).await {
Err(e @ influxdb3_client::Error::IO(io)) if io.kind() == std::io::ErrorKind::ConnectionReset => {
// transient: retry with backoff
}
Err(e) => return Err(e.into()),
Ok(v) => v,
} Prevention
- Always inspect the #[source] std::io::Error to distinguish transient from permanent failures.
- Build retry-with-backoff around client calls; pooled keep-alive connections frequently hit resets.
- Health-check the server before long batch operations.
- Keep reqwest/hyper updated for connection-pool fixes.
- Avoid proxies/TLS interception on the client path, or configure them correctly.
When it happens
Trigger: Calling any influxdb3_client HTTP method (query, write line protocol, health/ping, create/delete operations) when the underlying reqwest transport raises an IO error: connection dropped mid-request, DNS/socket failure surfaced as io::Error, or reading a response body from a closed stream.
Common situations: Server closed the connection abruptly or restarted mid-request; network interruption, VPN/firewall drop; keep-alive idle connection reused after server timeout; TLS interception proxies terminating the stream; container/OOM killing the server process during a request.
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
- error writing wal file
- Failed to bind address
- Failed to load table index from object store
- io error
- io error
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/161ab77c4dcab265.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_client/src/lib.rs:75
ApiError {
code: StatusCode,
message: String,
/// Machine-readable error code from JSON error responses, if present.
error_code: Option<String>,
},
#[error("failed to send {method} {url} request: {}", reqwest_description(.source))]
RequestSend {
method: Method,
url: String,
#[source]
source: reqwest::Error,
},
#[error("failed to build an http client: {}", reqwest_description(.0))]
Builder(#[source] reqwest::Error),
#[error("io error: {0}")]
IO(#[from] std::io::Error),
}
/// Try to parse a JSON error response body with `error_code` and `message` fields.
/// Returns `(message, error_code)`. If JSON parsing fails, treats the body as plain text.
pub(crate) fn parse_error_body(body: &str) -> (String, Option<String>) {
#[derive(serde::Deserialize)]
struct JsonError {
#[serde(default)]
error_code: Option<String>,
#[serde(default)]
message: Option<String>,
}
if let Ok(parsed) = serde_json::from_str::<JsonError>(body) {
let message = parsed.message.unwrap_or_else(|| body.to_string());
(message, parsed.error_code)
} else {
(body.to_string(), None)View on GitHub (pinned to 06200ef96b)