ducaale/xh · error

Connection timeout is not a valid number

Error message

Connection timeout is not a valid number

What it means

Final fallthrough guard in Timeout's FromStr impl: f64::from_str failed for the --connection-timeout argument, meaning the input is not a parseable number (e.g. 'abc' or an empty string), or it was NaN. The match on the parse result falls into the error arm and parsing of the timeout value aborts. Fires on any non-numeric or NaN timeout input.

Solutions

  1. Pass a plain numeric value in seconds (e.g. --timeout=30)
  2. Strip unit suffixes and convert to seconds before passing
  3. Quote/escape values in scripts to avoid empty strings
  4. Validate the value with f64 parsing (excluding NaN) beforehand

Example fix

# before
http --timeout=30s GET example.org
# after
http --timeout=30 GET example.org
Defensive patterns

Strategy: validation

Validate before calling

// validate the timeout is a plain number before invoking
let v: f64 = timeout_str.trim().parse().map_err(|_| "timeout must be a plain number of seconds, no unit suffix")?;
if v.is_nan() { return Err("timeout must not be NaN"); }

Type guard

fn is_valid_timeout(s: &str) -> bool {
    s.trim().parse::<f64>().map(|v| !v.is_nan()).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("not a valid number") {
    eprintln!("'{timeout_str}' is not a bare number of seconds");
}

Prevention

When it happens

Trigger: Passing --timeout=abc, --timeout='', --timeout=5s (suffix not allowed), or --timeout=NaN.

Common situations: Including time units like '30s' or '5m' (only bare numbers/seconds are accepted); locale-formatted decimals; empty values from unset env vars.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13). Data as JSON: /api/errors/c1e170224952eab1. Report an issue: GitHub.

Appendix: source

Thrown at src/cli.rs:1211

        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),
}

impl FromStr for Proxy {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> anyhow::Result<Self> {
        let split_arg: Vec<&str> = s.splitn(2, ':').collect();
        match split_arg[..] {
            [protocol, url] => {

View on GitHub (pinned to 2404aceecc)