gravitational/teleport · error

failed to retrieve stdout mode: %w

Error message

failed to retrieve stdout mode: %w

What it means

initTerminal calls winterm.GetConsoleMode on the Windows stdout handle (syscall.Stdout) before enabling VT processing. If the OS refuses to read the console mode, the call is aborted and this wrapped error is returned through Terminal.InitRaw. It means the process's standard output is not an interactive Windows console buffer (or the console API failed), so raw/VT terminal mode cannot be established.

Source

Thrown at lib/client/terminal/terminal_windows.go:49

	"github.com/Azure/go-ansiterm/winterm"
	"github.com/gravitational/trace"
	"github.com/moby/term"

	"github.com/gravitational/teleport/lib/client/tncon"
	"github.com/gravitational/teleport/lib/utils"
)

// initTerminal configures the terminal for raw, VT compatible output and
// optionally input. The returned function should be called before program
// exit to ensure the terminal is reset, otherwise it will be left in a broken
// state.
func initTerminal(input bool) (func(), error) {
	stdoutFd := int(syscall.Stdout)
	stdinFd := int(syscall.Stdin)

	oldOutMode, err := winterm.GetConsoleMode(uintptr(stdoutFd))
	if err != nil {
		return func() {}, fmt.Errorf("failed to retrieve stdout mode: %w", err)
	}

	oldInMode, err := winterm.GetConsoleMode(uintptr(stdinFd))
	if err != nil {
		return func() {}, fmt.Errorf("failed to retrieve stdout mode: %w", err)
	}

	newOutMode := oldOutMode | winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING | winterm.DISABLE_NEWLINE_AUTO_RETURN

	err = winterm.SetConsoleMode(uintptr(stdoutFd), newOutMode)
	if err != nil {
		return func() {}, fmt.Errorf("failed to set stdout mode: %w", err)
	}

	if input {
		newInMode := oldInMode
		newInMode &^= winterm.ENABLE_ECHO_INPUT
		newInMode &^= winterm.ENABLE_LINE_INPUT

View on GitHub (pinned to 1283425b60)

Solutions

  1. Run the client in a real interactive Windows console (conhost or Windows Terminal) with stdout attached to the console, not redirected.
  2. Before calling InitRaw, check term.IsTerminal(os.Stdout.Fd()) (moby/term) and skip raw mode when stdout is not a console.
  3. If running programmatically or in CI, use the library in non-interactive mode instead of requesting raw terminal capture.
  4. Ensure the process has an attached console (e.g. launch via a terminal rather than a detached/service context); use AttachConsole/AllocConsole if embedding.

Example fix

// before
cleanup, err := term.InitRaw(true)
if err != nil {
    return err
}

// after
if !term.IsTerminal(os.Stdout.Fd()) {
    return errors.New("stdout is not an interactive console; cannot enable raw mode")
}
cleanup, err := term.InitRaw(true)
if err != nil {
    return trace.Wrap(err)
}
Defensive patterns

Strategy: validation

Validate before calling

import "github.com/moby/term"

if !term.IsTerminal(os.Stdout.Fd()) {
    return errors.New("stdout is not an interactive Windows console; raw terminal mode unavailable")
}

Type guard

func isConsole(f *os.File) bool {
    return term.IsTerminal(f.Fd())
}

Try / catch

cleanup, err := t.InitRaw(input)
if err != nil {
    var consoleErr *fmt.Errorf
    if errors.As(err, &consoleErr) && strings.Contains(err.Error(), "failed to retrieve stdout mode") {
        log.Warn("no interactive console on stdout; disabling raw mode")
        cleanup = func() {}
    } else {
        return trace.Wrap(err)
    }
}

Prevention

When it happens

Trigger: Calling Terminal.InitRaw on Windows when GetConsoleMode(stdout) fails: stdout is redirected to a file or pipe, the process runs without an attached console (e.g. a service, scheduled task, or CI runner), or the console host returns an error for the pseudo handle.

Common situations: Running `tsh ssh` or another Teleport client interactively with `> out.log` redirection; invoking the client from a non-console parent (IDE run tool, ssh without a pty, Windows service); using a legacy terminal host that does not expose console mode APIs for the stdout handle.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/be37f4b88b31ebb5. Report an issue: GitHub.