{"record":{"id":"2136d2cf6b6caffe","repo":"charmbracelet/bubbletea","slug":"bubbletea-error-flushing-update-to-the-writer-w","errorCode":null,"errorMessage":"bubbletea: error flushing update to the writer: %w","messagePattern":"bubbletea: error flushing update to the writer: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cursed_renderer.go","lineNumber":569,"sourceCode":"\t\t}\n\t\tif hasUpdates {\n\t\t\t// Close synchronized output mode.\n\t\t\tbuf.WriteString(ansi.ResetModeSynchronizedOutput)\n\t\t}\n\t} else if (shouldUpdateCursorVis && showCursor) || (hasUpdates && showCursor && didShowCursor) {\n\t\t_, _ = buf.WriteString(ansi.SetModeTextCursorEnable)\n\t}\n\n\t// Reset internal screen renderer buffer.\n\ts.buf.Reset()\n\n\t// If our updates flush buffer has content, write it to the output writer.\n\tif buf.Len() > 0 {\n\t\tif s.logger != nil {\n\t\t\ts.logger.Printf(\"output: %q\", buf.String())\n\t\t}\n\t\tif _, err := io.Copy(s.w, &buf); err != nil {\n\t\t\treturn fmt.Errorf(\"bubbletea: error flushing update to the writer: %w\", err)\n\t\t}\n\t}\n\n\ts.lastView = &view\n\n\treturn nil\n}\n\n// render implements renderer.\nfunc (s *cursedRenderer) render(v View) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\ts.view = v\n}\n\n// reset implements renderer.\nfunc (s *cursedRenderer) reset() {","sourceCodeStart":551,"sourceCodeEnd":587,"githubUrl":"https://github.com/charmbracelet/bubbletea/blob/351d2159f8d8a85613aa2a6e98c8c63df3c98623/cursed_renderer.go#L551-L587","documentation":"Returned when the renderer's composed update buffer (cursor moves, erase sequences, synchronized-output wrappers) cannot be copied to the output writer during a flush with updates. This is the write of the actual frame delta after the screen buffer flush succeeded, so it fires specifically when the final io.Copy(s.w, &buf) of a frame fails. It propagates up and commonly ends the program wrapped as ErrProgramKilled.","triggerScenarios":"Output writer error during an update flush: broken pipe, closed pty, network writer failure, full disk for file output. Distinct from error 6 in that the internal screen flush succeeded but delivering the delta to the writer failed.","commonSituations":"Terminal emulator quit while the app was rendering; `app | grep -q found` style pipelines where the reader exits; custom WithOutput implementations (tee writers, sockets) erroring under load; slow consumers causing writes after close.","solutions":["Ensure the consumer of the output stream lives at least as long as Program.Run","Guard custom writers: return os.ErrClosed instead of panicking, and keep them thread-safe","Use tea.WithoutRenderer() for programmatic (non-visual) runs","Treat EPIPE on the output as a termination signal and quit the program gracefully via p.Quit()"],"exampleFix":"// before\ntype sockWriter struct{ c net.Conn }\nfunc (s sockWriter) Write(b []byte) (int, error) {\n    return s.c.Write(b) // errors kill the frame flush\n}\n\n// after\ntype sockWriter struct{ c net.Conn; dead atomic.Bool }\nfunc (s sockWriter) Write(b []byte) (int, error) {\n    if s.dead.Load() { return 0, os.ErrClosed }\n    n, err := s.c.Write(b)\n    if isDisconnect(err) { s.dead.Store(true) }\n    return n, err\n}","handlingStrategy":"try-catch","validationCode":"// Same pre-flight as flush: ensure writer accepts writes before Run\nif _, err := w.Write([]byte(\"\")); err != nil { return err }","typeGuard":"func isUpdateWriteFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"error flushing update to the writer\")\n}","tryCatchPattern":"_, err := p.Run()\nif isUpdateWriteFailure(err) {\n    if inner := errors.Unwrap(errors.Unwrap(err)); isDeadPipe(inner) {\n        return // output consumer exited\n    }\n    log.Printf(\"render update failed: %v\", err)\n}","preventionTips":["Make custom writers thread-safe and non-panicking; return os.ErrClosed when dead","Pair custom writers with a health check (ping write) on reconnect","Quit the program when output dies instead of letting every frame error","Keep pty masters open for the program's lifetime in tests"],"tags":["bubbletea","renderer","update","io","epipe","go"],"backgroundTag":null,"analyzedSha":"351d2159f8d8a85613aa2a6e98c8c63df3c98623","analyzedAt":"2026-08-15T10:48:22.366Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}