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

  1. Check the error source (std::io::Error) for the root cause (e.g. 'connection reset by peer', 'broken pipe').
  2. Retry the request — transient IO failures on pooled connections are common; use a retry with backoff.
  3. Verify the InfluxDB 3 server URL, port, and that the server is running and reachable (curl the health endpoint).
  4. Disable/inspect proxies or TLS interception; ensure firewall rules allow the connection.
  5. 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

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


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)