{"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":"exception","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/533346cc374382b41ec5ff70536252b2e96e725c/src/github_relay.rs#L80-L116","documentation":"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.","triggerScenarios":"configure runs and settings.github_relay.request_timeout parses to 0 — e.g. request_timeout = \"0s\", \"0\", or \"0ms\" in the config.","commonSituations":"Someone 'disabling' the timeout by setting it to zero; a templated config defaulting to 0; editing config values without understanding units.","solutions":["Set github_relay.request_timeout to a positive duration, e.g. \"30s\"","Ensure the value includes a valid unit (duration::parse_duration input) and is non-zero","Remove the override to fall back to the built-in default timeout"],"exampleFix":"// before\n[github_relay]\nrequest_timeout = \"0s\"\n// after\n[github_relay]\nrequest_timeout = \"30s\"","handlingStrategy":"validation","validationCode":"// Ensure the configured timeout parses and is non-zero\nlet t = humantime::parse_duration(&settings.github_relay.request_timeout)?;\nassert!(!t.is_zero(), \"request_timeout must be > 0, e.g. 30s\");","typeGuard":null,"tryCatchPattern":"match err {\n    RelayConfigError::ZeroTimeout => eprintln!(\"set github_relay.request_timeout to a positive duration like 30s\"),\n    e => return Err(e),\n}","preventionTips":["Never set timeouts to 0 as a 'disable' trick — use a large positive value instead","Include explicit units in duration strings","Add config validation in CI","Keep sane defaults; only override when necessary"],"tags":["github-relay","configuration","timeout","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}