charmbracelet/gum · error

failed to write to stdout: %w

Error message

failed to write to stdout: %w

What it means

When the action run by gum spin fails (m.err != nil), the error is printed to stderr; if even that Fprintf to stderr fails, Run returns this misleadingly-worded 'failed to write to stdout' wrapper. It signals the process cannot write to standard streams at all.

Source

Thrown at spin/command.go:56

	defer cancel()

	tm, err := tea.NewProgram(
		m,
		tea.WithOutput(os.Stderr),
		tea.WithContext(ctx),
		tea.WithInput(nil),
	).Run()
	if err != nil {
		return fmt.Errorf("unable to run action: %w", err)
	}

	m = tm.(model)
	// If the command succeeds, and we are printing output and we are in a TTY then push the STDOUT we got to the actual
	// STDOUT for piping or other things.
	//nolint:nestif
	if m.err != nil {
		if _, err := fmt.Fprintf(os.Stderr, "%s\n", m.err.Error()); err != nil {
			return fmt.Errorf("failed to write to stdout: %w", err)
		}
		return exit.ErrExit(1)
	} else if m.status == 0 {
		var output string
		if o.ShowOutput || (o.ShowStdout && o.ShowStderr) {
			output = m.output
		} else if o.ShowStdout {
			output = m.stdout
		} else if o.ShowStderr {
			output = m.stderr
		}
		if output != "" {
			if _, err := os.Stdout.WriteString(output); err != nil {
				return fmt.Errorf("failed to write to stdout: %w", err)
			}
		}
	} else if o.ShowError {
		// Otherwise if we are showing errors and the command did not exit with a 0 status code then push all of the command

View on GitHub (pinned to 4d089f9550)

Solutions

  1. Fix the underlying action error (printed via m.err) first — that's the real failure.
  2. Ensure stderr is open/attached when running gum spin (don't redirect it to a closed descriptor).
  3. Check disk space and file descriptor limits.
  4. Handle SIGPIPE/broken-pipe semantics in the surrounding pipeline.

Example fix

// before (stderr closed)
gum spin -- ./build.sh 2>&-
// after
gum spin -- ./build.sh 2>spin.log
Defensive patterns

Strategy: try-catch

Try / catch

if ! gum spin -- ./build.sh 2>spin.err; then cat spin.err >&2; fi  # keep stderr open and capture the real action error

Prevention

When it happens

Trigger: m.err set by the spin action AND the subsequent fmt.Fprintf(os.Stderr, ...) returning an error — e.g. closed/broken stderr pipe (`cmd 2>&- | ...`), full disk, or a broken pipe on the receiving end.

Common situations: Shell pipelines that closed stderr; containers with no stderr attached; disk-full conditions while a long spin action failed.

Related errors


AI-assisted analysis of charmbracelet/gum@4d089f9550 (2026-08-31). Data as JSON: /api/errors/fa2a657a11757b37. Report an issue: GitHub.