ducaale/xh · error
Connection timeout is negative
Error message
Connection timeout is negative
What it means
Validation guard in Timeout's FromStr impl: the --connection-timeout value parsed as f64 has a negative sign (e.g. '-5' or '-0.0' signed zero), so it cannot represent a valid duration and parsing aborts with an anyhow error before a Timeout is constructed. Fires whenever the user supplies a negative numeric timeout on the command line.
Solutions
- Supply a non-negative timeout value (e.g. --timeout=5)
- Clamp computed timeout values to >= 0 before passing them
- Omit --timeout to use the default
Example fix
# before http --timeout=-5 GET example.org # after http --timeout=5 GET example.org
Defensive patterns
Strategy: validation
Validate before calling
// validate the timeout string before invoking
let v: f64 = timeout_str.parse().map_err(|_| "invalid timeout")?;
if v.is_sign_negative() || v.is_nan() { return Err("timeout must be non-negative"); } Type guard
fn is_valid_timeout(s: &str) -> bool {
s.parse::<f64>().map(|v| !v.is_nan() && !v.is_sign_negative() && v < 1.7976931348623157e308).unwrap_or(false)
} Try / catch
let out = Command::new("http").args(["--timeout", &timeout_str, "GET", url]).output()?;
if !out.status.success() && String::from_utf8_lossy(&out.stderr).contains("timeout is negative") {
eprintln!("clamp timeout to >= 0 and retry");
} Prevention
- Clamp computed timeout values to a small positive minimum
- Guard against unset env vars defaulting to negative sentinels
- Validate numeric inputs with sign checks before passing
When it happens
Trigger: Passing --timeout=-5, --timeout=-0.001, or --timeout=-0 to any flag parsed into Timeout.
Common situations: Scripts parameterizing timeout with an unset/default negative sentinel; sign errors when computing timeout from offsets.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Connection timeout is too big
- Connection timeout is not a valid number
- Unknown auth type
- message-signature: Duplicate covered component identifier
- message-signature: RSA private keys require an explicit…
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/e792017cf42b41f8.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli.rs:1204
}
#[derive(Debug, Clone)]
pub struct Timeout(Duration);
impl Timeout {
pub fn as_duration(&self) -> Option<Duration> {
Some(self.0).filter(|t| !t.is_zero())
}
}
impl FromStr for Timeout {
type Err = anyhow::Error;
fn from_str(sec: &str) -> anyhow::Result<Timeout> {
match f64::from_str(sec) {
Ok(s) if !s.is_nan() => {
if s.is_sign_negative() {
Err(anyhow!("Connection timeout is negative"))
} else if s >= Duration::MAX.as_secs_f64() || s.is_infinite() {
Err(anyhow!("Connection timeout is too big"))
} else {
Ok(Timeout(Duration::from_secs_f64(s)))
}
}
_ => Err(anyhow!("Connection timeout is not a valid number")),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Proxy {
Http(Url),
Https(Url),
All(Url),
}
View on GitHub (pinned to 2404aceecc)