{"record":{"id":"af86319dab6db2a5","repo":"jdx/mise","slug":"took-longer-than-s","errorCode":null,"errorMessage":"took longer than {}s","messagePattern":"took longer than (.+?)s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/describe_command.rs","lineNumber":168,"sourceCode":"    let stdout = child.stdout.take().expect(\"piped\");\n    let (sender, receiver) = std::sync::mpsc::channel();\n    std::thread::spawn(move || {\n        let mut out = Vec::new();\n        let _ = stdout.take(DIFF_LIMIT as u64 + 1).read_to_end(&mut out);\n        let _ = sender.send(out);\n    });\n    let started = Instant::now();\n    let status = loop {\n        if let Some(status) = child.try_wait()? {\n            break status;\n        }\n        if started.elapsed() >= timeout {\n            // the shell and whatever it started; the reader thread ends\n            // with the last writer of the pipe, so it is not waited for\n            active.0.kill();\n            let _ = child.kill();\n            let _ = child.wait();\n            bail!(\"took longer than {}s\", timeout.as_secs());\n        }\n        std::thread::sleep(Duration::from_millis(100));\n    };\n    // a descendant that outlived the shell and kept the pipe is not the\n    // shell's answer: the output is waited for a moment, not forever\n    let Ok(output) = receiver.recv_timeout(output_grace) else {\n        active.0.kill();\n        bail!(\"a process it started kept its output open\");\n    };\n    if output.len() > DIFF_LIMIT {\n        bail!(\"description output exceeded {} bytes\", DIFF_LIMIT);\n    }\n    if !status.success() {\n        bail!(\"exited with {status}\");\n    }\n    let Some(line) = first_line(&output) else {\n        return Ok(None);\n    };","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/describe_command.rs#L150-L186","documentation":"run_with_limits executes a description command (via a shell) with a hard timeout, polling every 100ms. If the command has not finished when the timeout elapses, mise kills the shell and its process group and bails with 'took longer than Ns'. This prevents a hung describe command from stalling history operations indefinitely.","triggerScenarios":"The describe command configured for history (describe_command) runs longer than the configured timeout in seconds, e.g. a slow script, network call, or a prompt-waiting command.","commonSituations":"A describe command that prompts for input and blocks forever; commands hitting a slow network resource; timeouts set too low for legitimately slow generators; running on an overloaded CI machine.","solutions":["Increase the describe command's timeout setting to cover realistic worst-case runtime","Make the describe command non-interactive and fast (avoid prompts, add its own internal timeouts)","Test the command standalone to find why it hangs, then fix or replace it"],"exampleFix":"# before\ndefault_config = \"slow-describe.sh\"  # takes > timeout\n\n# after: raise the limit or bound the script\n[history]\ndescribe_timeout = \"30s\"  # or make slow-describe.sh finish quickly","handlingStrategy":"try-catch","validationCode":"start=$(date +%s); timeout 10 describe-command >/dev/null || echo \"describe command exceeds timeout; raise the limit or fix the script\" >&2","typeGuard":null,"tryCatchPattern":"match history::describe() {\n    Err(e) if e.to_string().contains(\"took longer than\") => {\n        // raise timeout or replace the command, then retry once\n    }\n    r => r?,\n}","preventionTips":["Keep describe commands fast, deterministic, and non-interactive","Set timeouts with headroom above worst-case runtime","Wrap long network calls in the script with their own timeouts"],"tags":["timeout","history","process"],"backgroundTag":"request-timeout","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"}