charmbracelet/bubbletea · error
bubbletea: error flushing screen writer: %w
Error message
bubbletea: error flushing screen writer: %w
What it means
Returned by the cursed renderer's periodic flush when s.scr.Flush() fails while publishing a rendered frame (the common per-framerate write path, not just shutdown). It means the differential screen updates for the current frame could not be written to the terminal buffer. This error surfaces through the renderer error channel and typically terminates the event loop wrapped in ErrProgramKilled.
Source
Thrown at cursed_renderer.go:481
if cur := view.Cursor; cur != nil {
// MoveTo must come after [uv.TerminalRenderer.Render] because the
// cursor position might get updated during rendering.
s.scr.MoveTo(view.Cursor.X, view.Cursor.Y)
} else if !view.AltScreen {
// We don't want the cursor to be dangling at the end of the line in
// inline mode because it can cause unwanted line wraps in some
// terminals. So we move it to the beginning of the next line if
// necessary.
// This is only needed when the cursor is hidden because when it's
// visible, we already set its position above.
x, y := s.scr.Position()
if x >= s.width-1 {
s.scr.MoveTo(0, y)
}
}
if err := s.scr.Flush(); err != nil {
return fmt.Errorf("bubbletea: error flushing screen writer: %w", err)
}
// Check if we have any render updates to flush.
hasUpdates := s.buf.Len() > 0
// Cursor visibility.
didShowCursor := s.lastView != nil && s.lastView.Cursor != nil
showCursor := view.Cursor != nil
hideCursor := !showCursor
shouldUpdateCursorVis := (s.lastView == nil || didShowCursor != showCursor) || shouldUpdateAltScreen
// Build final output buffer with synchronized output or hide/show cursor
// updates. But first, enter/exit alt screen mode if needed.
//
// Here, we have two scenarios:
// 1. Synchronized output updates are supported. In this case, we want to
// wrap all updates, unless it's just a cursor visibility change, in
// synchronized output mode. This is because synchronized output modeView on GitHub (pinned to 351d2159f8)
Solutions
- Verify the output writer is valid and open for the whole run
- Wrap runs that may lose their consumer with context cancellation so the program exits cleanly instead of erroring each frame
- For headless/non-TTY usage prefer tea.WithoutRenderer() or run with output to os.Stdout without a TTY
- Inspect the wrapped error: EPIPE/ErrClosed usually means the consumer exited — handle as exit condition, not a bug
Example fix
// before
p := tea.NewProgram(m, tea.WithOutput(sock)) // socket may die mid-frame
if _, err := p.Run(); err != nil { log.Fatal(err) }
// after
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGPIPE)
defer cancel()
p := tea.NewProgram(m, tea.WithContext(ctx), tea.WithOutput(sock))
_, err := p.Run()
if err != nil && !isClosedErr(err) { log.Fatal(err) } Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight the output before starting the loop:
if _, err := w.Write(nil); err != nil {
return fmt.Errorf("output unusable: %w", err)
}
p := tea.NewProgram(m, tea.WithOutput(w)) Type guard
func isDeadPipe(err error) bool {
return errors.Is(err, syscall.EPIPE) || errors.Is(err, os.ErrClosed) || errors.Is(err, syscall.EIO)
} Try / catch
_, err := p.Run()
if err != nil {
var outerErr error
if errors.As(err, &outerErr) || true {
if isDeadPipe(errors.Unwrap(err)) {
os.Exit(0) // terminal went away; normal end
}
}
log.Fatal(err)
} Prevention
- Detect consumer death (SIGPIPE handling) and call p.Quit promptly
- Avoid tea.WithOutput to streams with independent lifetimes
- For file output, monitor ENOSPC and alert the user
- Test render paths with a bytes.Buffer writer
When it happens
Trigger: Terminal/pty closed or resized away between frames; tea.WithOutput writer erroring during normal rendering; EPIPE from a dead pipe consumer; device IO errors on Windows console handles; disk-full when output is redirected to a file.
Common situations: User closes the terminal window mid-run; program output piped into a tool that exits; remote pty (SSH/Wish) torn down; writing frames to a log file on a full filesystem; flaky serial-console deployments.
Related errors
- bubbletea: error closing screen writer: %w
- bubbletea: error writing to screen: %w
- bubbletea: error flushing update to the writer: %w
- bubbletea: error writing insert above to the writer: %w
- error writing to output: %w
AI-assisted analysis of charmbracelet/bubbletea@351d2159f8 (2026-08-15).
Data as JSON: /api/errors/bf1617fde272c37f.
Report an issue: GitHub.