jdx/mise · error

relay request timeout must be greater than zero

Error message

relay request timeout must be greater than zero

What it means

configure parses settings.github_relay.request_timeout (via duration::parse_duration) and bails if the resulting Duration is zero. A zero timeout would make every relay request fail immediately, so it is rejected as configuration error. Note the error is about the configured value, not a CLI flag here.

Solutions

  1. Set github_relay.request_timeout to a positive duration, e.g. "30s"
  2. Ensure the value includes a valid unit (duration::parse_duration input) and is non-zero
  3. Remove the override to fall back to the built-in default timeout

Example fix

// before
[github_relay]
request_timeout = "0s"
// after
[github_relay]
request_timeout = "30s"
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the configured timeout parses and is non-zero
let t = humantime::parse_duration(&settings.github_relay.request_timeout)?;
assert!(!t.is_zero(), "request_timeout must be > 0, e.g. 30s");

Try / catch

match err {
    RelayConfigError::ZeroTimeout => eprintln!("set github_relay.request_timeout to a positive duration like 30s"),
    e => return Err(e),
}

Prevention

When it happens

Trigger: configure runs and settings.github_relay.request_timeout parses to 0 — e.g. request_timeout = "0s", "0", or "0ms" in the config.

Common situations: Someone 'disabling' the timeout by setting it to zero; a templated config defaulting to 0; editing config values without understanding units.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/1e0c3f0799c25518. Report an issue: GitHub.

Appendix: source

Thrown at src/github_relay.rs:98

    no_log_requests: bool,
    format: Option<&str>,
    max_duration: Option<&str>,
) -> Result<Option<Scope>> {
    let Some(scope) = scope else {
        if log_requests || no_log_requests || format.is_some() || max_duration.is_some() {
            bail!("relay options require --github-relay-read-only");
        }
        return Ok(None);
    };
    let settings = crate::config::Settings::get();
    let settings = &settings.github_relay;
    let format = format.unwrap_or(&settings.log_format);
    if !matches!(format, "text" | "jsonl") {
        bail!("relay log format must be text or jsonl");
    }
    let timeout = duration::parse_duration(&settings.request_timeout)?;
    if timeout.is_zero() {
        bail!("relay request timeout must be greater than zero");
    }
    if !(1..=32).contains(&settings.concurrency) {
        bail!("relay concurrency must be between 1 and 32");
    }
    let max_duration = duration::parse_duration(max_duration.unwrap_or(&settings.max_duration))?;
    if std::time::Instant::now().checked_add(timeout).is_none()
        || std::time::Instant::now()
            .checked_add(max_duration)
            .is_none()
    {
        bail!("relay duration is too large");
    }
    #[cfg(not(unix))]
    let _ = max_duration;
    #[cfg(unix)]
    let scope = {
        let mut scope = scope;
        scope.options = Options {

View on GitHub (pinned to 533346cc37)