{"record":{"id":"bdf65243cae36972","repo":"gravitational/teleport","slug":"canceled","errorCode":null,"errorMessage":"canceled","messagePattern":"canceled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"lib/utils/prompt/prompt.go","lineNumber":35,"sourceCode":" */\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 {\n\t\trenderRow = func(t T) string {\n\t\t\treturn fmt.Sprintf(\"%v\", t)\n\t\t}","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/utils/prompt/prompt.go#L17-L53","documentation":"prompt.ErrCanceled is a sentinel error returned when the user selects the quit option in an interactive selection prompt (as opposed to aborting with ctrl-c, which yields ErrInterrupted). Callers are expected to detect it with errors.Is so a deliberate quit is not treated as a system failure.","triggerScenarios":"User chooses the quit/cancel entry in a SelectModel-based prompt, causing Run to return trace.Wrap(ErrCanceled).","commonSituations":"Users backing out of an interactive workflow (e.g. selecting 'quit' in tsh menus); test harnesses simulating the quit selection; confusion with ErrInterrupted since both represent cancellation paths.","solutions":["Handle it with errors.Is(err, prompt.ErrCanceled) and treat it as a normal, expected exit.","Differentiate from ErrInterrupted if your UX needs distinct messaging for quit vs ctrl-c.","Guard interactive prompts behind an interactivity check (isatty / --non-interactive flag) so prompts are never shown where quitting is the only outcome."],"exampleFix":"// before\nresult, err := prompt.Run(...)\nif err != nil { return err }\n// after\nresult, err := prompt.Run(...)\nif err != nil {\n  switch {\n  case errors.Is(err, prompt.ErrCanceled):\n    return nil\n  case errors.Is(err, prompt.ErrInterrupted):\n    return nil\n  }\n  return err\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isPromptCanceled(err error) bool {\n    return errors.Is(err, prompt.ErrCanceled)\n}","tryCatchPattern":"if err != nil {\n    if errors.Is(err, prompt.ErrCanceled) {\n        return nil // user chose quit\n    }\n    return trace.Wrap(err)\n}","preventionTips":["Detect quit selection with errors.Is(err, prompt.ErrCanceled) and exit cleanly.","Handle ErrCanceled and ErrInterrupted together where cancellation semantics are identical.","Provide non-interactive flags so users never have to quit a prompt in scripts."],"tags":["prompt","interactive","user-cancellation"],"backgroundTag":"user-canceled-prompt","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}