{"record":{"id":"125358651cfd3c8f","repo":"charmbracelet/bubbletea","slug":"program-was-killed","errorCode":null,"errorMessage":"program was killed","messagePattern":"program was killed","errorType":"error_code","errorClass":"ErrProgramKilled","httpStatus":null,"severity":"warning","filePath":"tea.go","lineNumber":42,"sourceCode":"\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/charmbracelet/colorprofile\"\n\tuv \"github.com/charmbracelet/ultraviolet\"\n\t\"github.com/charmbracelet/x/ansi\"\n\t\"github.com/charmbracelet/x/term\"\n\t\"github.com/muesli/cancelreader\"\n)\n\n// ErrProgramPanic is returned by [Program.Run] when the program recovers from a panic.\nvar ErrProgramPanic = errors.New(\"program experienced a panic\")\n\n// ErrProgramKilled is returned by [Program.Run] when the program gets killed.\nvar ErrProgramKilled = errors.New(\"program was killed\")\n\n// ErrInterrupted is returned by [Program.Run] when the program get a SIGINT\n// signal, or when it receives a [InterruptMsg].\nvar ErrInterrupted = errors.New(\"program was interrupted\")\n\n// Msg contain data from the result of a IO operation. Msgs trigger the update\n// function and, henceforth, the UI.\ntype Msg = uv.Event\n\n// Model contains the program's state as well as its core functions.\ntype Model interface {\n\t// Init is the first function that will be called. It returns an optional\n\t// initial command. To not perform an initial command return nil.\n\tInit() Cmd\n\n\t// Update is called when a message is received. Use it to inspect messages\n\t// and, in response, update the model and/or send a command.\n\tUpdate(Msg) (Model, Cmd)","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/charmbracelet/bubbletea/blob/351d2159f8d8a85613aa2a6e98c8c63df3c98623/tea.go#L24-L60","documentation":"ErrProgramKilled is a sentinel returned by Program.Run when the program was terminated abnormally rather than quitting gracefully: someone called Program.Kill(), the context passed to RunContext/WithContext was cancelled, or the internal event loop failed. It signals that shutdown skipped the final render and terminal restoration ran in 'kill' mode. It is frequently wrapped together with the underlying cause (a context error or the error that killed the loop).","triggerScenarios":"Calling p.Kill() from another goroutine; cancelling the context given to tea.NewProgram(...).RunContext or tea.WithContext; the eventLoop returning a non-nil error (input read failure, renderer failure); a recovered panic (wrapped as ErrProgramKilled: ErrProgramPanic).","commonSituations":"Embedding a Bubble Tea program in a server where a supervisor cancels the ctx on shutdown; test harnesses that time out and cancel; calling Kill instead of Quit to stop a stuck program; SSH sessions (Wish) dropping and cancelling per-connection contexts.","solutions":["If you intended a clean exit, use p.Quit() or tea.Quit cmd instead of p.Kill()/context cancel","If cancellation is expected, treat errors.Is(err, tea.ErrProgramKilled) as a normal shutdown path, not a failure","If it wraps a real cause, unwrap with errors.Unwrap / errors.Is to find the underlying error and fix that (often an input/renderer failure)","Ensure you are not cancelling the parent context while Run is still expected to render its final frame"],"exampleFix":"// before\np := tea.NewProgram(m)\ngo func() { time.AfterFunc(time.Second, func() { p.Kill() }) }()\n\n// after\np := tea.NewProgram(m)\ngo func() { time.AfterFunc(time.Second, func() { p.Quit() }) }()","handlingStrategy":"try-catch","validationCode":"// Decide the shutdown channel before running:\n// graceful -> p.Quit(); forced -> p.Kill()/ctx cancel (yields ErrProgramKilled)","typeGuard":"func isProgramKilled(err error) bool {\n    return err != nil && errors.Is(err, tea.ErrProgramKilled)\n}","tryCatchPattern":"_, err := p.Run()\nif isProgramKilled(err) {\n    // unwrap cause if present\n    cause := errors.Unwrap(err)\n    _ = cause\n    // treat as abnormal-but-expected shutdown\n    return nil\n}","preventionTips":["Prefer p.Quit() / tea.Quit for normal exits; reserve Kill for hangs","Scope the context you pass via tea.WithContext to the program's real lifetime","Document for your users which exit paths return ErrProgramKilled","Don't spawn goroutines that cancel the context on unrelated errors"],"tags":["bubbletea","lifecycle","shutdown","go","tui"],"backgroundTag":null,"analyzedSha":"351d2159f8d8a85613aa2a6e98c8c63df3c98623","analyzedAt":"2026-08-15T10:48:22.366Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}