FiloSottile/age · warning
SetConsoleMode failed
Error message
SetConsoleMode failed
What it means
On Windows, the terminal enablement code calls the Win32 SetConsoleMode API to turn on processed output and virtual terminal (ANSI) processing for stdout. If the syscall returns zero (failure), it reports "SetConsoleMode failed". This typically means the output handle is not a real console (redirected/piped) or the Windows version lacks VT support.
Source
Thrown at internal/term/term_windows.go:44
ENABLE_PROCESSED_OUTPUT uint32 = 0x1
ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
)
kernel32DLL := windows.NewLazySystemDLL("Kernel32.dll")
setConsoleMode := kernel32DLL.NewProc("SetConsoleMode")
var mode uint32
if err := syscall.GetConsoleMode(syscall.Handle(out.Fd()), &mode); err != nil {
return err
}
mode |= ENABLE_PROCESSED_OUTPUT
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
// If the SetConsoleMode function fails, the return value is zero.
// See https://learn.microsoft.com/en-us/windows/console/setconsolemode#return-value.
if ret, _, _ := setConsoleMode.Call(out.Fd(), uintptr(mode)); ret == 0 {
return errors.New("SetConsoleMode failed")
}
return nil
}
}
View on GitHub (pinned to b74dce4cdb)
Solutions
- Check Windows.GetConsoleMode first: only attempt SetConsoleMode when the handle is a real console; treat failure on non-console handles as non-fatal.
- Remove ENABLE_VIRTUAL_TERMINAL_PROCESSING and retry with just ENABLE_PROCESSED_OUTPUT on legacy consoles.
- Run in a Windows 10+ terminal (Windows Terminal) that supports VT processing.
Example fix
// before
if ret, _, _ := setConsoleMode.Call(out.Fd(), uintptr(mode)); ret == 0 {
return errors.New("SetConsoleMode failed")
}
// after
if ret, _, _ := setConsoleMode.Call(out.Fd(), uintptr(mode)); ret == 0 {
return nil // not a console or unsupported: degrade gracefully
} Defensive patterns
Strategy: fallback
Validate before calling
var mode uint32
if err := windows.GetConsoleMode(windows.Handle(os.Stdout.Fd()), &mode); err != nil {
// not a console: skip VT setup entirely
} Type guard
func isConsole(f *os.File) bool {
var mode uint32
return windows.GetConsoleMode(windows.Handle(f.Fd()), &mode) == nil
} Try / catch
if err := setupConsole(out); err != nil {
// degrade gracefully: ANSI codes may not render, but proceed
log.Printf("console VT setup unavailable: %v", err)
} Prevention
- Only attempt SetConsoleMode on handles confirmed to be consoles.
- Treat console-mode failure as non-fatal on redirected output.
- Test on Windows Terminal and legacy conhost before shipping.
When it happens
Trigger: Calling into internal/term's console setup on Windows when out.Fd() is a non-console handle (pipe, file) or the legacy console does not support ENABLE_VIRTUAL_TERMINAL_PROCESSING.
Common situations: Running an age plugin with stdout redirected to a file or pipe; very old Windows (pre-Windows 10) consoles; embedded terminal emulators that do not emulate console mode.
Related errors
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/5cb0ac5ce1ceb6ef.
Report an issue: GitHub.