{"record":{"id":"0f355af4505f20df","repo":"RightNow-AI/openfang","slug":"failed-to-draw-0f355a","errorCode":null,"errorMessage":"Failed to draw","messagePattern":"Failed to draw","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/openfang-cli/src/tui/mod.rs","lineNumber":2423,"sourceCode":"    let mut app = App::new(config, tx);\n\n    // Initial screen\n    if wizard::needs_setup() {\n        app.wizard.reset();\n        app.phase = Phase::Boot(BootScreen::Wizard);\n    } else {\n        app.phase = Phase::Boot(BootScreen::Welcome);\n        // Non-blocking daemon detection\n        app.start_daemon_detect();\n    }\n\n    // ── Main loop ────────────────────────────────────────────────────────────\n    // Draw first, then block on events. This ensures the first frame appears\n    // immediately, before any event processing.\n    while !app.should_quit {\n        terminal\n            .draw(|frame| app.draw(frame))\n            .expect(\"Failed to draw\");\n\n        // Block until at least one event arrives (or 33ms timeout for ~30fps)\n        match rx.recv_timeout(Duration::from_millis(33)) {\n            Ok(ev) => app.handle_event(ev),\n            Err(mpsc::RecvTimeoutError::Timeout) => {}\n            Err(mpsc::RecvTimeoutError::Disconnected) => break,\n        }\n        // Drain all queued events immediately (batch processing)\n        while let Ok(ev) = rx.try_recv() {\n            app.handle_event(ev);\n        }\n    }\n\n    ratatui::restore();\n}\n","sourceCodeStart":2405,"sourceCodeEnd":2439,"githubUrl":"https://github.com/RightNow-AI/openfang/blob/acf2587e46be174c10200489c9a2d23a39a98aeb/crates/openfang-cli/src/tui/mod.rs#L2405-L2439","documentation":"The TUI main loop calls ratatui's `Terminal::draw`, which renders a frame and flushes it to the terminal backend. `draw` returns `io::Result` and the code unwraps it with `.expect(\"Failed to draw\")`, so any I/O or terminal-control failure while painting a frame panics. Ratatui raises this when the terminal backend cannot perform the write or query the terminal state (e.g. stdout is not a real TTY).","triggerScenarios":"Running the CLI's TUI when stdout/stderr is redirected to a file or pipe (not a TTY), the terminal is closed/disconnected mid-loop, the descriptor hits an I/O error, or a raw-mode/alternate-screen restore fails so ratatui cannot write escape sequences.","commonSituations":"Developers piping `openfang` output to a log or `| tee`, running inside CI or non-interactive shells, running over SSH sessions that drop, or embedding the TUI in a test harness with a captured (non-tty) stdout.","solutions":["Run the binary in a real interactive terminal (no redirection/pipes on stdout).","Add a TTY check before entering the TUI loop and fall back to a non-interactive mode if `atty::is(Stdout)` is false.","Replace `.expect` with proper error propagation and exit gracefully with a message instead of panicking.","If running over SSH, reconnect in a stable terminal and relaunch; ensure TERM is set correctly."],"exampleFix":"// before\nterminal\n    .draw(|frame| app.draw(frame))\n    .expect(\"Failed to draw\");\n\n// after\nif !atty::is(atty::Stream::Stdout) {\n    eprintln!(\"TUI requires an interactive terminal\");\n    return Err(anyhow!(\"stdout is not a TTY\"));\n}\nterminal\n    .draw(|frame| app.draw(frame))\n    .context(\"TUI draw failed\")?;","handlingStrategy":"fallback","validationCode":"fn can_draw_tui() -> bool {\n    atty::is(atty::Stream::Stdout)\n        && std::env::var(\"TERM\").map(|t| !t.is_empty()).unwrap_or(false)\n}\n// call before run_tui(); if false, use non-interactive mode","typeGuard":null,"tryCatchPattern":"// Rust has no try/catch; avoid expect and propagate\nterminal.draw(|frame| app.draw(frame))\n    .context(\"TUI draw failed\")?;","preventionTips":["Check stdout is a TTY before entering any ratatui loop","Never pipe/redirect the TUI binary's stdout","Handle resize and disconnect events gracefully","Replace .expect on draw with error propagation and clean terminal restore"],"tags":["tui","io","ratatui","terminal"],"backgroundTag":"stdout-not-a-tty","analyzedSha":"acf2587e46be174c10200489c9a2d23a39a98aeb","analyzedAt":"2026-09-02T22:42:28.464Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}