{"record":{"id":"cc0906c57fc5cb0c","repo":"charmbracelet/bubbletea","slug":"error-getting-terminal-state-w","errorCode":null,"errorMessage":"error getting terminal state: %w","messagePattern":"error getting terminal state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tty_windows.go","lineNumber":40,"sourceCode":"\t\t}\n\n\t\t// Enable VT input\n\t\tvar mode uint32\n\t\tif err := windows.GetConsoleMode(windows.Handle(p.ttyInput.Fd()), &mode); err != nil {\n\t\t\treturn fmt.Errorf(\"error getting console mode: %w\", err)\n\t\t}\n\n\t\tif err := windows.SetConsoleMode(windows.Handle(p.ttyInput.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {\n\t\t\treturn fmt.Errorf(\"error setting console mode: %w\", err)\n\t\t}\n\t}\n\n\t// Save output screen buffer state and enable VT processing.\n\tif f, ok := p.output.(term.File); ok && term.IsTerminal(f.Fd()) {\n\t\tp.ttyOutput = f\n\t\tp.previousOutputState, err = term.GetState(f.Fd())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting terminal state: %w\", err)\n\t\t}\n\n\t\tvar mode uint32\n\t\tif err := windows.GetConsoleMode(windows.Handle(p.ttyOutput.Fd()), &mode); err != nil {\n\t\t\treturn fmt.Errorf(\"error getting console mode: %w\", err)\n\t\t}\n\n\t\tif err := windows.SetConsoleMode(windows.Handle(p.ttyOutput.Fd()),\n\t\t\tmode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|\n\t\t\t\twindows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {\n\t\t\treturn fmt.Errorf(\"error setting console mode: %w\", err)\n\t\t}\n\n\t\t//nolint:godox\n\t\t// TODO: check if we can optimize cursor movements on Windows.\n\t\tp.checkOptimizedMovements(p.previousOutputState)\n\t}\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/charmbracelet/bubbletea/blob/351d2159f8d8a85613aa2a6e98c8c63df3c98623/tty_windows.go#L22-L58","documentation":"On Windows, after input setup, initInput() saves the output screen buffer state with term.GetState(p.ttyOutput.Fd()) so it can be restored when the program exits. This error means that snapshot failed — the output handle is not a readable console screen buffer at that moment. Program.Run() aborts because Bubble Tea cannot guarantee it can restore the user's terminal afterwards.","triggerScenarios":"Program output implements term.File and passes term.IsTerminal(), but GetState's internal GetConsoleMode on the screen buffer fails: the output handle was closed/replaced between the IsTerminal check and the call, or the handle points to a non-console sink that was misdetected.","commonSituations":"A harness or parent process swapping/closing the ConPTY output handle during startup, piping stdout while a wrapper pty still makes it look like a terminal, and services started with redirected-but-then-detached output.","solutions":["Ensure the output handle stays a live console screen buffer for the whole run — do not close the ConPTY until Program.Run() returns.","If output is genuinely redirected, pass the actual writer via tea.WithOutput(w) (or nil) instead of letting the program inherit a half-valid handle.","Run from a normal interactive console session to confirm the code path works before blaming configuration.","For headless runs, tea.WithoutRenderer() skips this initialization entirely."],"exampleFix":"// before\nf, _ := os.OpenFile(\"out.log\", os.O_WRONLY, 0o644)\np := tea.NewProgram(model{}, tea.WithOutput(f)) // later state save fails on dead handle\n\n// after: keep exactly one stable output target for the program lifetime\np := tea.NewProgram(model{}, tea.WithOutput(os.Stdout))","handlingStrategy":"validation","validationCode":"if f, ok := os.Stdout.(term.File); ok && !term.IsTerminal(f.Fd()) {\n    // stdout cannot be snapshotted/restored; run headless\n    p := tea.NewProgram(model, tea.WithoutRenderer(), tea.WithOutput(nil))\n}","typeGuard":"func isConsoleScreenBuffer(f term.File) bool {\n    var mode uint32\n    return windows.GetConsoleMode(windows.Handle(f.Fd()), &mode) == nil\n}","tryCatchPattern":"if _, err := p.Run(); err != nil {\n    if strings.Contains(err.Error(), \"error getting terminal state\") {\n        log.Fatal(\"stdout is not a live console screen buffer; keep the output handle stable or run with tea.WithoutRenderer()\")\n    }\n    log.Fatalf(\"run: %v\", err)\n}","preventionTips":["Give the program one stable output target for its whole lifetime; do not swap or close stdout mid-run.","Keep test ConPTY output handles open until the program exits.","Validate the output handle with GetConsoleMode before p.Run() when embedding in unusual hosts."],"tags":["windows","console","screen-buffer","tty","bubbletea","initialization"],"backgroundTag":null,"analyzedSha":"351d2159f8d8a85613aa2a6e98c8c63df3c98623","analyzedAt":"2026-08-15T10:48:22.366Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}