{"record":{"id":"179708155093a2f0","repo":"gravitational/teleport","slug":"interrupted","errorCode":null,"errorMessage":"interrupted","messagePattern":"interrupted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"lib/utils/prompt/prompt.go","lineNumber":32,"sourceCode":" *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\npackage prompt\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/gravitational/trace\"\n)\n\n// ErrInterrupted is an error when prompt is interrupted with ctrl-c or a signal.\nvar ErrInterrupted = errors.New(\"interrupted\")\n\n// ErrCanceled is an error when quit option was selected.\nvar ErrCanceled = errors.New(\"canceled\")\n\n// SelectModel is a generic struct that holds the options, context, and state.\ntype SelectModel[T any] struct {\n\tcaption     string\n\toptions     []T\n\tcursor      int\n\tselected    *T\n\trenderRow   func(T) string\n\tquitting    bool\n\tinterrupted bool\n}\n\n// NewSelectPrompt initializes the generic model with options, a renderer, and a context.\nfunc NewSelectPrompt[T any](caption string, options []T, renderRow func(T) string) SelectModel[T] {\n\tif renderRow == nil {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/utils/prompt/prompt.go#L14-L50","documentation":"prompt.ErrInterrupted is a sentinel error returned by the interactive prompt's Run when the user aborts a selection with ctrl-c or when the process receives an interrupt signal while the bubbletea prompt is active. It lets callers distinguish user cancellation from real failures. Check it with errors.Is (the returned error is wrapped via trace.Wrap).","triggerScenarios":"User presses ctrl-c during a tsh/interactive prompt, or an OS interrupt signal cancels the prompt model, causing Run to return trace.Wrap(ErrInterrupted).","commonSituations":"Users aborting a certificate/cluster selection prompt in CI where stdin is a terminal that then receives SIGINT; automated scripts piping ctrl-c behavior; long-running prompts aborted by operators.","solutions":["Treat this as expected user cancellation: return/exit gracefully without logging it as an error.","Use errors.Is(err, prompt.ErrInterrupted) to detect it (the error is wrapped).","In non-interactive contexts, avoid opening the prompt at all so no interrupt path is triggered."],"exampleFix":"// before\nselected, err := prompt.Run(...)\nif err != nil { return err }\n// after\nselected, err := prompt.Run(...)\nif err != nil {\n  if errors.Is(err, prompt.ErrInterrupted) {\n    return nil // user canceled, not a failure\n  }\n  return err\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isPromptInterrupted(err error) bool {\n    return errors.Is(err, prompt.ErrInterrupted)\n}","tryCatchPattern":"if err != nil {\n    if errors.Is(err, prompt.ErrInterrupted) {\n        return nil // graceful exit on ctrl-c\n    }\n    return trace.Wrap(err)\n}","preventionTips":["Always check ErrInterrupted/ErrCanceled (via errors.Is) around prompt.Run calls.","Skip interactive prompts when stdin is not a TTY.","Log interruptions at info level, not as errors."],"tags":["prompt","interactive","user-cancellation","signal"],"backgroundTag":"user-interrupted-prompt","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}