charmbracelet/bubbletea · error

bubbletea: error writing insert above to the writer: %w

Error message

bubbletea: error writing insert above to the writer: %w

What it means

Returned by the renderer's insertAbove path (used by tea.ScrollUp / SyncScrollArea-style output above the frame) when writing the pre-built scrollback lines to the output writer fails. Unlike normal frames, this content bypasses the screen diff and is written directly, so a writer failure here loses scrollback lines permanently. The error wraps the underlying io.WriteString failure.

Source

Thrown at cursed_renderer.go:759

	// on the cursor position.
	up := offset + h - 1
	sb.WriteString(ansi.CursorUp(up))
	sb.WriteString(ansi.InsertLine(offset))
	for _, line := range lines {
		sb.WriteString(line)
		sb.WriteString(ansi.EraseLineRight)
		sb.WriteString("\r\n")
	}

	s.scr.SetPosition(0, 0)

	if s.logger != nil {
		s.logger.Printf("insert above: %q", sb.String())
	}

	_, err := io.WriteString(s.w, sb.String())
	if err != nil {
		return fmt.Errorf("bubbletea: error writing insert above to the writer: %w", err)
	}

	return nil
}

// onMouse implements renderer.
func (s *cursedRenderer) onMouse(m MouseMsg) Cmd {
	var onMouse func(MouseMsg) Cmd
	s.mu.Lock()
	if s.lastView != nil {
		onMouse = s.lastView.OnMouse
	}
	s.mu.Unlock()
	if onMouse != nil {
		return onMouse(m)
	}
	return nil
}

View on GitHub (pinned to 351d2159f8)

Solutions

  1. Verify the writer used with tea.WithOutput is open before issuing scroll-up commands
  2. Rate-limit or buffer insert-above output for flaky writers
  3. Handle EPIPE/ErrClosed by quitting the program instead of continuing to scroll
  4. Reproduce with a bytes.Buffer writer in tests to rule out writer-side bugs

Example fix

// before
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    return m, tea.ScrollUpCmd(lines) // fails when output is broken
}

// after
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    if m.outputOK {
        return m, tea.ScrollUpCmd(lines)
    }
    return m, tea.Quit
}
Defensive patterns

Strategy: validation

Validate before calling

// Before issuing insert-above, confirm output health:
func canScrollAbove(w io.Writer) bool {
    _, err := w.Write(nil)
    return err == nil
}

Type guard

func isInsertAboveFailure(err error) bool {
    return err != nil && strings.Contains(err.Error(), "error writing insert above to the writer")
}

Try / catch

if err := tea.NewProgram(m).Run(); isInsertAboveFailure(err) {
    if isDeadPipe(errors.Unwrap(errors.Unwrap(err))) {
        os.Exit(0)
    }
    log.Fatal(err)
}

Prevention

When it happens

Trigger: Calling tea.ScrollUpCmd / rendering content above the frame while the output writer is closed or broken; inserting log lines above the TUI when stdout is a dead pipe; pty torn down during scrollback emission.

Common situations: Apps that print log lines above the UI (ScrollUp) running with redirected output; terminal closed right as a burst of above-frame messages is emitted; custom writers that fail intermittently under load.

Related errors


AI-assisted analysis of charmbracelet/bubbletea@351d2159f8 (2026-08-15). Data as JSON: /api/errors/86c49dbeca78b487. Report an issue: GitHub.