charmbracelet/bubbletea · error

error setting console mode

Error message

error setting console mode: %w

What it means

Windows initInput() enables virtual terminal (VT) input by OR-ing ENABLE_VIRTUAL_TERMINAL_INPUT into the console mode and calling windows.SetConsoleMode on stdin. This error means the mode update was rejected — most commonly because the console does not support VT input (pre-Windows-10 consoles, legacy conhost) or the handle is invalid. Since VT escape sequences are how Bubble Tea reads keys and mouse, initialization fails and Program.Run() returns this error.

Solutions

  1. Run in Windows Terminal, a recent conhost on Windows 10 1511+, or a ConPTY-based host — VT input is a hard requirement of this code path.
  2. On older Windows, run the program inside Windows Terminal via WSL, or wrap it in a ConPTY yourself and pass that pty to tea.WithInput/tea.WithOutput.
  3. Verify support before starting: call GetConsoleMode and attempt a SetConsoleMode with ENABLE_VIRTUAL_TERMINAL_INPUT yourself; if it fails, fall back to tea.WithInput(nil) and a plain UI.
  4. Check the wrapped error code — ERROR_INVALID_PARAMETER means unsupported flag (old console); ERROR_INVALID_HANDLE means a dead handle.

Example fix

// before
p := tea.NewProgram(model{})
if _, err := p.Run(); err != nil {
    log.Fatalf("%v", err) // error setting console mode: The parameter is incorrect
}

// after: probe VT support, degrade gracefully
if !vtInputSupported() {
    p = tea.NewProgram(model{}, tea.WithoutRenderer())
}
if _, err := p.Run(); err != nil { log.Fatal(err) }

func vtInputSupported() bool {
    var mode uint32
    h := windows.Handle(os.Stdin.Fd())
    if err := windows.GetConsoleMode(h, &mode); err != nil { return false }
    return windows.SetConsoleMode(h, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT) == nil
}
Defensive patterns

Strategy: fallback

Validate before calling

func vtInputSupported() bool {
    var mode uint32
    h := windows.Handle(os.Stdin.Fd())
    if err := windows.GetConsoleMode(h, &mode); err != nil { return false }
    ok := windows.SetConsoleMode(h, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT) == nil
    _ = windows.SetConsoleMode(h, mode) // restore
    return ok
}

var opts []tea.ProgramOption
if !vtInputSupported() {
    opts = append(opts, tea.WithoutRenderer())
}
p := tea.NewProgram(model, opts...)

Try / catch

if _, err := p.Run(); err != nil {
    if strings.Contains(err.Error(), "error setting console mode") {
        // ENABLE_VIRTUAL_TERMINAL_INPUT rejected: legacy console
        log.Fatal("this console does not support VT input; use Windows Terminal or a ConPTY host")
    }
    log.Fatalf("run: %v", err)
}

Prevention

When it happens

Trigger: windows.SetConsoleMode(stdin, mode|ENABLE_VIRTUAL_TERMINAL_INPUT) fails on Windows versions older than 10 1511, on some legacy or restricted console hosts, or when the input handle was invalidated between the GetConsoleMode and SetConsoleMode calls.

Common situations: Running the .exe on Windows 7/8 or Windows Server 2012/2012 R2, terminals that host their own non-VT console emulation, locked-down terminal servers where SetConsoleMode is denied, and CI agents using a bare conhost without VT enabled.

Related errors


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

Appendix: source

Thrown at tty_windows.go:31

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)
		}

		if err := windows.SetConsoleMode(windows.Handle(p.ttyOutput.Fd()),
			mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|

View on GitHub (pinned to 351d2159f8)