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

  1. Supply a non-negative timeout value (e.g. --timeout=5)
  2. Clamp computed timeout values to >= 0 before passing them
  3. 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

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.

Related errors


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)