{"record":{"id":"90d40b78d83eed1f","repo":"kovidgoyal/kitty","slug":"canceled-by-user","errorCode":null,"errorMessage":"Canceled by user","messagePattern":"Canceled by user","errorType":"error_code","errorClass":"ErrCanceledByUser","httpStatus":null,"severity":"info","filePath":"kittens/unicode_input/main.go","lineNumber":491,"sourceCode":"\t\t\tself.err = err\n\t\t\tself.lp.Quit(1)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (self *handler) next_mode(delta int) {\n\tfor num, md := range all_modes {\n\t\tif md.mode == self.mode {\n\t\t\tidx := (num + delta + len(all_modes)) % len(all_modes)\n\t\t\tmd = all_modes[idx]\n\t\t\tself.switch_mode(md.mode)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nvar ErrCanceledByUser = errors.New(\"Canceled by user\")\n\nfunc (self *handler) on_key_event(event *loop.KeyEvent) (err error) {\n\tif event.MatchesPressOrRepeat(\"esc\") || event.MatchesPressOrRepeat(\"ctrl+c\") {\n\t\treturn ErrCanceledByUser\n\t}\n\tif event.MatchesPressOrRepeat(\"f1\") || event.MatchesPressOrRepeat(\"ctrl+1\") {\n\t\tevent.Handled = true\n\t\tself.switch_mode(HEX)\n\t} else if event.MatchesPressOrRepeat(\"f2\") || event.MatchesPressOrRepeat(\"ctrl+2\") {\n\t\tevent.Handled = true\n\t\tself.switch_mode(NAME)\n\t} else if event.MatchesPressOrRepeat(\"f3\") || event.MatchesPressOrRepeat(\"ctrl+3\") {\n\t\tevent.Handled = true\n\t\tself.switch_mode(EMOTICONS)\n\t} else if event.MatchesPressOrRepeat(\"f4\") || event.MatchesPressOrRepeat(\"ctrl+4\") {\n\t\tevent.Handled = true\n\t\tself.switch_mode(FAVORITES)\n\t} else if event.MatchesPressOrRepeat(\"ctrl+tab\") || event.MatchesPressOrRepeat(\"ctrl+]\") {","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/unicode_input/main.go#L473-L509","documentation":"ErrCanceledByUser is a sentinel error in the unicode_input kitten's Go handler returned from on_key_event when the user presses Escape or Ctrl+C, and from main when the session aborts that way. It is not a failure — it is the kitten's normal cancellation signal, and callers treat it as a clean exit (typically mapping it to exit code 1 or a no-op) rather than an error to report.","triggerScenarios":"Opening the unicode input/emoji kitten and pressing esc or ctrl+c; on_key_event matches those keys and returns ErrCanceledByUser immediately, terminating the chooser without inserting a character.","commonSituations":"Scripts or wrappers invoking `kitten unicode_input` non-interactively and receiving this error because input closed/escaped; programmatically driving the kitten and interpreting the cancellation sentinel as a crash; key remappings that send esc more easily than intended.","solutions":["Treat ErrCanceledByUser as a normal cancellation: check `errors.Is(err, ErrCanceledByUser)` and exit quietly (e.g. exit code 1) rather than printing an error","If it appears unexpectedly, check what's sending esc/ctrl+c to the kitten (key bindings, automated input)","For scripted use, avoid launching the interactive kitten without a TTY or provide a codepoint via arguments instead"],"exampleFix":"// before\nif err := main(); err != nil { fmt.Fprintln(os.Stderr, err) } // prints 'Canceled by user'\n\n// after\nif err := main(); err != nil {\n    if !errors.Is(err, ErrCanceledByUser) {\n        fmt.Fprintln(os.Stderr, err)\n    }\n    os.Exit(1)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isUserCancel(err error) bool {\n    return errors.Is(err, unicode_input.ErrCanceledByUser)\n}","tryCatchPattern":"if err := run(); err != nil {\n    if errors.Is(err, unicode_input.ErrCanceledByUser) {\n        return nil // clean cancel, no message\n    }\n    return err\n}","preventionTips":["Always check errors.Is against ErrCanceledByUser before reporting","Don't drive the interactive kitten from scripts without a TTY","Treat exit-on-esc as expected UX, not a failure"],"tags":["kitty","unicode-input","sentinel-error","cancellation","go"],"backgroundTag":"user-cancelled-operation","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}