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
- Pipe content into the pager: `cat file | gum pager` or `gum pager < file`
- Pass content explicitly via the pager options instead of relying on stdin
- Check the upstream pipeline stage emits non-empty output
- 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
- Always pipe input or set content explicitly for the pager
- Verify upstream pipeline output is non-empty
- Wrap stdin.Read errors with %w so causes aren't discarded (library-side fix)
- Pre-check stdin is not a TTY before invoking
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
- stdin is empty
- no input provided, see `gum style --help`
- failed to read line: %w
- failed to write rune: %w
- no options provided, see `gum choose --help`
AI-assisted analysis of charmbracelet/gum@4d089f9550 (2026-08-31).
Data as JSON: /api/errors/3c83959101b94525.
Report an issue: GitHub.