{"record":{"id":"45fd0bb19351b510","repo":"jdx/mise","slug":"check-timeout-must-be-greater-than-zero","errorCode":null,"errorMessage":"Check timeout must be greater than zero","messagePattern":"Check timeout must be greater than zero","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/doctor/project.rs","lineNumber":235,"sourceCode":"    }\n}\n\nasync fn run_check(\n    check: &DoctorCheck,\n    root: &Path,\n    environment: &EnvMap,\n) -> Result<std::process::Output> {\n    if check.run.trim().is_empty() {\n        bail!(\"Check command must not be empty\");\n    }\n    let timeout = check\n        .timeout\n        .as_deref()\n        .map(crate::duration::parse_duration)\n        .transpose()?\n        .unwrap_or(Duration::from_secs(10));\n    if timeout.is_zero() {\n        bail!(\"Check timeout must be greater than zero\");\n    }\n    let mut shell = match &check.shell {\n        Some(shell) => crate::path::split_shell_command(shell)?,\n        None => Settings::get().default_inline_shell()?,\n    };\n    Settings::get().maybe_no_profile(&mut shell);\n    let Some((program, args)) = shell\n        .split_first()\n        .filter(|(program, _)| !program.trim().is_empty())\n    else {\n        bail!(\"Check shell must not be empty\");\n    };\n    CmdLineRunner::new(program)\n        .cmd_body_args(args, &check.run)\n        .current_dir(\n            check\n                .dir\n                .as_ref()","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/cli/doctor/project.rs#L217-L253","documentation":"Doctor project checks accept an optional `timeout`; mise parses it with parse_duration and defaults to 10 seconds. If the parsed timeout is zero, run_check bails because a zero-duration timeout would either be invalid for the runner or instantly kill the check process.","triggerScenarios":"A doctor check with `timeout = \"0\"`, `timeout = \"0s\"`, or any value that parse_duration resolves to Duration::zero(), passed into run_check from check.","commonSituations":"Misunderstanding timeout units (writing 0 expecting 'no limit'); a templated/variable timeout defaulting to 0; copy-pasted config where the timeout was zeroed out.","solutions":["Set the check's `timeout` to a positive duration, e.g. `timeout = \"30s\"`.","Remove the `timeout` field to use the default 10 seconds.","If the timeout comes from a variable/template, give it a positive default instead of 0."],"exampleFix":"// before\n[[doctor.checks]]\nname = \"test\"\nrun = \"npm test\"\ntimeout = \"0s\"\n\n// after\n[[doctor.checks]]\nname = \"test\"\nrun = \"npm test\"\ntimeout = \"30s\"","handlingStrategy":"validation","validationCode":"// verify timeout is a positive duration before invoking doctor\nassert!(check.timeout.is_none() || parse_duration(check.timeout.as_ref().unwrap()).unwrap() > Duration::ZERO);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use explicit units in timeout values (e.g. \"30s\", \"2m\").","Never set timeouts to 0 expecting 'unlimited' — omit the field for the default.","Give templated timeout variables positive defaults."],"tags":["doctor","timeout","validation","cli"],"backgroundTag":"value-out-of-range","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"}