{"record":{"id":"7a236129533b0002","repo":"jlcodes99/cockpit-tools","slug":"other","errorCode":"Other","errorMessage":"process output reader panicked","messagePattern":"process output reader panicked","errorType":"error_code","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/modules/process_timeout.rs","lineNumber":89,"sourceCode":"        status,\n        stdout,\n        stderr,\n    })\n}\n\nfn join_reader_with_deadline(\n    reader: Option<JoinHandle<io::Result<Vec<u8>>>>,\n    deadline: Instant,\n) -> io::Result<Vec<u8>> {\n    let Some(handle) = reader else {\n        return Ok(Vec::new());\n    };\n    loop {\n        if handle.is_finished() {\n            return handle\n                .join()\n                .map_err(|_| {\n                    io::Error::new(io::ErrorKind::Other, \"process output reader panicked\")\n                })?\n                .map_err(|error| error);\n        }\n        if Instant::now() >= deadline {\n            // Detach the reader thread; it will exit when the pipe is eventually closed.\n            drop(handle);\n            return Err(io::Error::new(\n                io::ErrorKind::TimedOut,\n                \"process output drain timed out\",\n            ));\n        }\n        std::thread::sleep(Duration::from_millis(20));\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src-tauri/src/modules/process_timeout.rs#L71-L107","documentation":"join_reader_with_deadline joins the stdout/stderr reader thread of output_with_timeout. If the reader thread panicked (handle.join() returns Err), the panic is converted into an io::Error of kind Other with the message 'process output reader panicked'. This indicates a bug or unexpected condition inside the output-reading code, not a process-level failure.","triggerScenarios":"The reader thread spawned by output_with_timeout panics while reading child output — e.g. an unwrap/expect inside the reader failing on malformed pipe state — and the parent then joins the thread within its deadline.","commonSituations":"Unexpected OS pipe errors combined with non-defensive reader code; library-version regressions in pipe handling; extremely large or rapidly closing output streams.","solutions":["Report/inspect the reader thread panic — check for unwrap/expect inside output-reading code and make it error-returning instead of panicking.","Retry the command once; if reproducible, it indicates a code defect that must be fixed upstream.","As a caller, match on this error kind (Other with this message) and degrade gracefully rather than crashing.","Update the crate to a version where the reader thread is panic-free."],"exampleFix":"// before\nlet out = output_with_timeout(&mut cmd, timeout)?; // panics propagate here as Err(Other)\n\n// after\nlet out = match output_with_timeout(&mut cmd, timeout) {\n    Ok(o) => o,\n    Err(e) if e.to_string() == \"process output reader panicked\" => {\n        log::error!(\"reader thread bug; retrying\");\n        output_with_timeout(&mut cmd, timeout)?\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match output_with_timeout(&mut cmd, timeout) {\n    Err(e) if e.to_string() == \"process output reader panicked\" => {\n        log::error!(\"internal reader panic; retry once or report bug\");\n        output_with_timeout(&mut cmd, timeout)\n    }\n    other => other,\n}","preventionTips":["Keep pipe-reading code free of unwrap/expect — return io::Error instead","Update the crate so reader-thread panics are fixed upstream","Treat this error as a bug signal: log and report rather than silently retrying forever","Add tests with abrupt pipe closures and huge outputs to shake out reader panics"],"tags":["panic","thread","io-error","process"],"backgroundTag":"thread-panicked","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}