charmbracelet/bubbletea · error
error getting console mode: %w
Error message
error getting console mode: %w
What it means
After raw mode succeeded, the Windows initInput() path reads the console input mode with windows.GetConsoleMode on stdin before enabling ENABLE_VIRTUAL_TERMINAL_INPUT. This error means that read failed — the handle is no longer a valid console input buffer between the MakeRaw and GetConsoleMode calls. It aborts Program.Run().
Source
Thrown at tty_windows.go:27
"github.com/charmbracelet/x/term"
"golang.org/x/sys/windows"
)
func (p *Program) initInput() (err error) {
// Save stdin state and enable VT input
// We also need to enable VT
// input here.
if f, ok := p.input.(term.File); ok && term.IsTerminal(f.Fd()) {
p.ttyInput = f
p.previousTtyInputState, err = term.MakeRaw(p.ttyInput.Fd())
if err != nil {
return fmt.Errorf("error making terminal raw: %w", err)
}
// Enable VT input
var mode uint32
if err := windows.GetConsoleMode(windows.Handle(p.ttyInput.Fd()), &mode); err != nil {
return fmt.Errorf("error getting console mode: %w", err)
}
if err := windows.SetConsoleMode(windows.Handle(p.ttyInput.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
return fmt.Errorf("error setting console mode: %w", err)
}
}
// Save output screen buffer state and enable VT processing.
if f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) {
p.ttyOutput = f
p.previousOutputState, err = term.GetState(f.Fd())
if err != nil {
return fmt.Errorf("error getting terminal state: %w", err)
}
var mode uint32
if err := windows.GetConsoleMode(windows.Handle(p.ttyOutput.Fd()), &mode); err != nil {
return fmt.Errorf("error getting console mode: %w", err)View on GitHub (pinned to 351d2159f8)
Solutions
- Reproduce with a plain interactive console first — if it only fails under your harness, the harness is closing or detaching the console handle.
- Keep the ConPTY alive for the whole Program.Run() lifetime in integration tests (do not close the pty right after spawning).
- Defer program start until the console is fully attached (e.g. after windows.FreeConsole/AttachConsole sequences complete).
- As a fallback for non-interactive runs, use tea.WithInput(nil) plus tea.WithoutRenderer().
Example fix
// before: test closes the pty immediately after starting the program
go func() { p.Run() }()
pty.Close() // console handle invalidated mid-init -> error getting console mode
// after: keep the pty alive until the program exits
done := make(chan struct{})
go func() { defer close(done); p.Run() }()
<-done
pty.Close() Defensive patterns
Strategy: try-catch
Validate before calling
var mode uint32
if err := windows.GetConsoleMode(windows.Handle(os.Stdin.Fd()), &mode); err != nil {
// handle will also fail inside initInput; skip terminal mode
p := tea.NewProgram(model, tea.WithInput(nil))
} Type guard
func validConsoleHandle(fd uintptr) bool {
var mode uint32
return windows.GetConsoleMode(windows.Handle(fd), &mode) == nil
} Try / catch
if _, err := p.Run(); err != nil {
if strings.Contains(err.Error(), "error getting console mode") && runtime.GOOS == "windows" {
// stdin console handle died mid-init: fix the harness that closes the ConPTY early
log.Fatal("console input handle invalidated during startup; keep the ConPTY open for the program lifetime")
}
log.Fatalf("run: %v", err)
} Prevention
- In ConPTY harnesses, close the pty only after Program.Run() returns, never right after spawning.
- Avoid closing or detaching stdin's console while the program initializes.
- Probe the handle with GetConsoleMode immediately before p.Run() to catch dead handles early with a clear message.
When it happens
Trigger: Called immediately after term.MakeRaw(p.ttyInput.Fd()) succeeds; fails when the console handle is invalidated concurrently (window closed, ConPTY terminated, handle freed by a parent process) or when fd conversion yields an invalid windows.Handle.
Common situations: A test harness or parent process closes the ConPTY while the program is starting, a scheduler/service context with a half-attached console, and races during process shutdown (Ctrl+C while the program initializes).
Related errors
- error making terminal raw: %w
- error getting terminal state: %w
- error setting console mode: %w
- error entering raw mode: %w
- program experienced a panic
AI-assisted analysis of charmbracelet/bubbletea@351d2159f8 (2026-08-15).
Data as JSON: /api/errors/553c94fd895e6a50.
Report an issue: GitHub.