{"record":{"id":"1e0c3f0799c25518","repo":"jdx/mise","slug":"relay-request-timeout-must-be-greater-than-zero","errorCode":null,"errorMessage":"relay request timeout must be greater than zero","messagePattern":"relay request timeout must be greater than zero","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/github_relay.rs","lineNumber":98,"sourceCode":"    no_log_requests: bool,\n    format: Option<&str>,\n    max_duration: Option<&str>,\n) -> Result<Option<Scope>> {\n    let Some(scope) = scope else {\n        if log_requests || no_log_requests || format.is_some() || max_duration.is_some() {\n            bail!(\"relay options require --github-relay-read-only\");\n        }\n        return Ok(None);\n    };\n    let settings = crate::config::Settings::get();\n    let settings = &settings.github_relay;\n    let format = format.unwrap_or(&settings.log_format);\n    if !matches!(format, \"text\" | \"jsonl\") {\n        bail!(\"relay log format must be text or jsonl\");\n    }\n    let timeout = duration::parse_duration(&settings.request_timeout)?;\n    if timeout.is_zero() {\n        bail!(\"relay request timeout must be greater than zero\");\n    }\n    if !(1..=32).contains(&settings.concurrency) {\n        bail!(\"relay concurrency must be between 1 and 32\");\n    }\n    let max_duration = duration::parse_duration(max_duration.unwrap_or(&settings.max_duration))?;\n    if std::time::Instant::now().checked_add(timeout).is_none()\n        || std::time::Instant::now()\n            .checked_add(max_duration)\n            .is_none()\n    {\n        bail!(\"relay duration is too large\");\n    }\n    #[cfg(not(unix))]\n    let _ = max_duration;\n    #[cfg(unix)]\n    let scope = {\n        let mut scope = scope;\n        scope.options = Options {","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/github_relay.rs#L80-L116","documentation":"configure parses the relay request timeout from settings.github_relay.request_timeout (or explicit overrides) and requires it to be strictly greater than zero. A zero timeout would disable request timing entirely, so mise rejects it as invalid configuration. A companion check also bounds relay concurrency to 1..=32.","triggerScenarios":"duration::parse_duration succeeds but the resulting Duration is zero — i.e. [github_relay].request_timeout = \"0\" / \"0s\" / \"0ms\" in mise.toml or settings, then npm_command or cli_observability_overrides calls configure.","commonSituations":"Someone setting request_timeout = \"0\" believing it means 'unlimited'; copy-pasting template configs with placeholder zero values; unit mistakes like \"0s\" when intending seconds-long defaults.","solutions":["Set [github_relay].request_timeout to a positive duration, e.g. \"30s\" or \"1m\".","If you meant no timeout cap, look for the max_duration setting instead — request_timeout must still be > 0.","Omit the setting to use mise's built-in default request timeout."],"exampleFix":"// before (mise.toml)\n[github_relay]\nrequest_timeout = \"0\"\n// after\n[github_relay]\nrequest_timeout = \"30s\"","handlingStrategy":"validation","validationCode":"let t = duration::parse_duration(&settings.github_relay.request_timeout)?;\nassert!(!t.is_zero(), \"request_timeout must be > 0\");","typeGuard":"fn has_positive_timeout(s: &GithubRelaySettings) -> bool {\n    duration::parse_duration(&s.request_timeout).map_or(false, |d| !d.is_zero())\n}","tryCatchPattern":"match configure(scope, lr, nlr, format, max_duration) {\n    Err(e) if e.to_string().contains(\"timeout must be greater than zero\") => {\n        // reset request_timeout to a sane default and retry\n    }\n    r => r,\n}","preventionTips":["Never set request_timeout to 0; it must be a positive duration like \"30s\".","Add config validation (or schema lint) for [github_relay] durations.","Remember zero is invalid here even if you expect it to mean 'unlimited'; use defaults instead."],"tags":["configuration","github-relay","validation","duration"],"backgroundTag":"invalid-config-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}