charmbracelet/bubbletea · info · ErrInterrupted
program was interrupted
Error message
program was interrupted
What it means
ErrInterrupted is returned by Program.Run when the program received SIGINT (Ctrl+C) or an explicit tea.InterruptMsg, and exited because of it. It distinguishes a user-initiated interrupt from a graceful quit (which returns nil) so callers can decide exit codes. It is only produced when the built-in signal handler is active (not disabled with WithoutSignalHandler).
Source
Thrown at tea.go:46
"syscall"
"time"
"github.com/charmbracelet/colorprofile"
uv "github.com/charmbracelet/ultraviolet"
"github.com/charmbracelet/x/ansi"
"github.com/charmbracelet/x/term"
"github.com/muesli/cancelreader"
)
// ErrProgramPanic is returned by [Program.Run] when the program recovers from a panic.
var ErrProgramPanic = errors.New("program experienced a panic")
// ErrProgramKilled is returned by [Program.Run] when the program gets killed.
var ErrProgramKilled = errors.New("program was killed")
// ErrInterrupted is returned by [Program.Run] when the program get a SIGINT
// signal, or when it receives a [InterruptMsg].
var ErrInterrupted = errors.New("program was interrupted")
// Msg contain data from the result of a IO operation. Msgs trigger the update
// function and, henceforth, the UI.
type Msg = uv.Event
// Model contains the program's state as well as its core functions.
type Model interface {
// Init is the first function that will be called. It returns an optional
// initial command. To not perform an initial command return nil.
Init() Cmd
// Update is called when a message is received. Use it to inspect messages
// and, in response, update the model and/or send a command.
Update(Msg) (Model, Cmd)
// View renders the program's UI, which can be a string or a [Layer]. The
// view is rendered after every Update.
View() ViewView on GitHub (pinned to 351d2159f8)
Solutions
- If Ctrl+C should be handled by the model instead of exiting, filter it in Update on KeyMsg with tea.KeyCtrlC and return tea.Quit yourself (Run then returns nil)
- If you want the interrupt status, check errors.Is(err, tea.ErrInterrupted) after Run and map it to exit code 130
- Use tea.WithoutSignalHandler() and wire your own signal handling if you need custom SIGINT semantics
- Do not treat this error as a bug — it is a normal termination signal
Example fix
// before
if _, err := p.Run(); err != nil {
log.Fatal(err) // treats Ctrl+C as fatal
}
// after
_, err := p.Run()
if err != nil && !errors.Is(err, tea.ErrInterrupted) {
log.Fatal(err)
}
os.Exit(130) Defensive patterns
Strategy: try-catch
Validate before calling
// If you need custom Ctrl+C behavior, install no changes here — handle KeyMsg // in Update and don't let the default quit path surprise you: // p := tea.NewProgram(m) // default signal handler active
Type guard
func isInterrupted(err error) bool {
return err != nil && errors.Is(err, tea.ErrInterrupted)
} Try / catch
_, err := p.Run()
if isInterrupted(err) {
os.Exit(130) // conventional SIGINT exit status
}
if err != nil { log.Fatal(err) } Prevention
- Map ErrInterrupted to exit code 130 in CLIs for shell-friendliness
- To intercept Ctrl+C, match tea.KeyCtrlC in Update and return your own Cmd/Quit
- Remember ErrInterrupted only appears with the built-in signal handler enabled
- Don't conflate interrupted (user action) with killed (programmatic)
When it happens
Trigger: User presses Ctrl+C while the program owns the terminal in raw mode; the process receives SIGINT from the shell or a supervisor; the model sends tea.InterruptMsg (e.g. via a tea.Interrupt command) to terminate with this status.
Common situations: CLI tools wanting exit code 130 on Ctrl+C; programs where Ctrl+C should mean 'cancel current operation' but the default handler quits; running under debuggers or supervisors that deliver SIGINT; shells sending SIGINT to whole process groups.
Related errors
- program was killed
- program experienced a panic
- bubbletea: InitialModel cannot be nil
- bubbletea: error closing screen writer: %w
- bubbletea: error writing to screen: %w
AI-assisted analysis of charmbracelet/bubbletea@351d2159f8 (2026-08-15).
Data as JSON: /api/errors/80d47df6ed8027f2.
Report an issue: GitHub.