{"record":{"id":"80d61e9fd92b7ab1","repo":"xai-org/grok-build","slug":"terminal-input-reader-did-not-park-before-suspend","errorCode":null,"errorMessage":"terminal input reader did not park before suspend","messagePattern":"terminal input reader did not park before suspend","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/app/event_loop.rs","lineNumber":371,"sourceCode":"    reader_parked.load(Ordering::Acquire)\n}\n\n/// Suspend the TUI, let a blocking child own the tty, then restore it.\n///\n/// Input is parked before the asynchronous frame writer is drained with a bounded wait, so neither the reader nor a queued frame can race the child.\n/// A park or drain timeout returns without starting the child; the caller keeps the request pending and retries it later.\nfn suspend_for_child(\n    screen_mode: crate::app::ScreenMode,\n    terminal: &mut PagerTerminal,\n    input_paused: &std::sync::atomic::AtomicBool,\n    reader_parked: &std::sync::atomic::AtomicBool,\n    input_rx: &mut tokio::sync::mpsc::UnboundedReceiver<TimedInputEvent>,\n    run_child: impl FnOnce(),\n) -> std::io::Result<Option<(u16, u16)>> {\n    use std::sync::atomic::Ordering;\n    if !park_input_reader(input_paused, reader_parked, Duration::from_millis(500)) {\n        input_paused.store(false, Ordering::Release);\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::TimedOut,\n            \"terminal input reader did not park before suspend\",\n        ));\n    }\n    let writer_sync = terminal.backend_mut().writer_mut().writer_sync().clone();\n    match writer_sync.wait_drained(Duration::from_millis(750)) {\n        Ok(crate::render::draw::WriterDrain::Drained) => {}\n        Ok(crate::render::draw::WriterDrain::TimedOut) => {\n            input_paused.store(false, Ordering::Release);\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::TimedOut,\n                \"terminal writer did not drain before suspend\",\n            ));\n        }\n        Err(error) => {\n            input_paused.store(false, Ordering::Release);\n            return Err(error);\n        }","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/app/event_loop.rs#L353-L389","documentation":"An io::Error of kind TimedOut returned by suspend_for_child when park_input_reader fails to get the terminal input reader to acknowledge the pause within 500ms. The suspend sequence requires the reader parked before handing the terminal to a child process; if it doesn't park, the handoff is aborted and the pause flag is rolled back.","triggerScenarios":"Input reader thread/event loop not reaching its park state within 500 ms — e.g. a flood of queued input events, a blocked input_rx consumer, or scheduler starvation under heavy load.","commonSituations":"User typing/pasting rapidly while an editor or child process is about to launch; slow CI/SSH terminals delaying event loop wakeup; regression in the input reader loop.","solutions":["Retry the suspend (the pause flag is rolled back, so state is consistent)","Check that the input reader loop responds promptly to the pause flag and calls reader_parked","Reduce input event backlog before suspending","Increase the 500ms park window if the environment is legitimately slow"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = suspend_for_child(...) {\n  if e.kind() == std::io::ErrorKind::TimedOut { retry_suspend_once(); }\n}","preventionTips":["Drain queued input events before requesting suspend","Keep the input reader loop responsive to the pause flag","Avoid suspend under heavy input replay/paste storms"],"tags":["terminal","suspend","timeout","input"],"backgroundTag":"terminal-suspend-timeout","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}