charmbracelet/bubbletea
Debugging
Bubble Tea apps own stdin and stdout, so traditional fmt.Println debugging does not work. The library ships three escape hatches.
LogToFile
The simplest option. Add a few lines at the start of main to redirect Go's default logger to a file:
if path := os.Getenv("DEBUG"); path != "" {
f, err := tea.LogToFile("debug.log", "debug")
if err != nil {
fmt.Println("fatal:", err)
os.Exit(1)
}
defer f.Close()
}Then tail -f debug.log while the program runs. LogToFile opens the file in append-mode (logging.go) and sets log's output and prefix. LogToFileWith accepts any logger that satisfies the LogOptionsSetter interface — useful for charm's log package.
TEA_TRACE
When the env var TEA_TRACE is set to a writable file path, Program configures an internal trace logger (tea.go near tracePath, traceOk := os.LookupEnv("TEA_TRACE")). The trace records every byte the renderer flushes to stdout and every input event the cancel reader receives. Useful for diagnosing tearing, off-by-one cursor moves, and "why did my program emit that escape?".
TEA_TRACE=/tmp/tea.log ./myappThe file is opened with O_APPEND, so multiple runs accumulate. Rotate it manually.
TEA_DEBUG (panic dumps)
When TEA_DEBUG=1 and a panic occurs, recoverFromPanic writes a bubbletea-panic-<unix>.log next to the working directory containing the message and stack trace. The terminal is restored before the stack trace is written, so it is also visible inline.
Delve (headless)
Because Bubble Tea takes over the TTY, you cannot run dlv debug ./myapp in the same terminal you are debugging. Run delve in headless mode and connect from another shell:
# Terminal A
dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
# Terminal B
dlv connect 127.0.0.1:43000The README's "Debugging with Delve" section captures this verbatim.
Common gotchas
- Panics leave the terminal cooked: this only happens if you set
WithoutCatchPanics(). The default panic recovery resets the TTY before printing the stack. - Garbled output after
tea.Exec: confirm yourExecCommandis actually setting stdout/stderr; the runtime defaults them to the program's TTY inosExecCommand.SetStdout/SetStderr(exec.go). - Mouse not working in tmux: mouse mode is requested via DEC modes; tmux must have
set -g mouse on. The renderer cannot fix this for you. - Focus events missing in tmux: tmux requires
set -g focus-events on. - Windows resize is missed:
signals_windows.gois a stub — Windows does not deliver SIGWINCH. The runtime polls incheckResize(tty.go) instead. - Suspend (Ctrl+Z) does nothing on Windows:
suspendSupportedis false on Windows; sendingSuspendMsgbecomes a no-op.
Logging selected events
Rather than logging every message, gate on type:
case tea.KeyPressMsg:
log.Printf("key: %s mod=%v", msg.String(), msg.Mod)Msg is the ultraviolet.Event interface, so %T prints the underlying type — handy for "what kind of message is this?" debugging.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.