charmbracelet/gum · error

unable to read stdin

Error message

unable to read stdin

What it means

Returned by the pager command's Run when stdin.Read fails and o.Content is empty. Note the original error is discarded — the pager reports only that stdin could not be read, so the underlying cause (e.g. 'stdin is empty') is hidden. The pager requires either explicit Content or readable piped stdin.

Source

Thrown at pager/command.go:23

	"regexp"

	"charm.land/bubbles/v2/help"
	"charm.land/bubbles/v2/viewport"
	tea "charm.land/bubbletea/v2"
	"charm.land/gum/v2/internal/stdin"
	"charm.land/gum/v2/internal/timeout"
)

// Run provides a shell script interface for the viewport bubble.
// https://github.com/charmbracelet/bubbles/viewport
func (o Options) Run() error {
	vp := viewport.New(viewport.WithWidth(o.Style.Width), viewport.WithHeight(o.Style.Height))
	vp.Style = o.Style.ToLipgloss()

	if o.Content == "" {
		stdin, err := stdin.Read()
		if err != nil {
			return fmt.Errorf("unable to read stdin")
		}
		if stdin != "" {
			// Sanitize the input from stdin by removing backspace sequences.
			backspace := regexp.MustCompile(".\x08")
			o.Content = backspace.ReplaceAllString(stdin, "")
		} else {
			return fmt.Errorf("provide some content to display")
		}
	}

	m := model{
		viewport:            vp,
		help:                help.New(),
		content:             o.Content,
		origContent:         o.Content,
		showLineNumbers:     o.ShowLineNumbers,
		lineNumberStyle:     o.LineNumberStyle.ToLipgloss(),
		softWrap:            o.SoftWrap,

View on GitHub (pinned to 4d089f9550)

Solutions

  1. Pipe content into the pager: `cat file | gum pager` or `gum pager < file`
  2. Pass content explicitly via the pager options instead of relying on stdin
  3. Check the upstream pipeline stage emits non-empty output
  4. In Go callers, check stdin.Read's error before constructing pager Options and log its cause

Example fix

// before
// no input: gum pager  -> "unable to read stdin"
// after
gum pager < README.md
# or programmatically
content, err := stdin.Read()
if err != nil { return fmt.Errorf("unable to read stdin: %w", err) }
Defensive patterns

Strategy: validation

Validate before calling

fi, _ := os.Stdin.Stat()
if (fi.Mode() & os.ModeCharDevice) != 0 { return fmt.Errorf("pager needs input: pipe a file or set content") }

Type guard

func stdinHasData() bool {
    fi, err := os.Stdin.Stat()
    return err == nil && (fi.Mode()&os.ModeCharDevice) == 0 && fi.Size() != 0
}

Try / catch

err := pagerCmd.Run()
if err != nil && err.Error() == "unable to read stdin" {
    return fmt.Errorf("no pager content: pipe input or pass content explicitly")
}

Prevention

When it happens

Trigger: Running the pager with no --content and no piped stdin (stdin is a TTY or empty pipe): e.g. `gum pager` run interactively without `< file`.

Common situations: Invoking the pager in a script without redirecting input; upstream pipeline stage produced nothing; running under a scheduler where stdin is /dev/null.

Related errors


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