kovidgoyal/kitty · info · ErrCanceledByUser
Canceled by user
Error message
Canceled by user
What it means
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.
Source
Thrown at kittens/unicode_input/main.go:491
self.err = err
self.lp.Quit(1)
return
}
}
}
func (self *handler) next_mode(delta int) {
for num, md := range all_modes {
if md.mode == self.mode {
idx := (num + delta + len(all_modes)) % len(all_modes)
md = all_modes[idx]
self.switch_mode(md.mode)
break
}
}
}
var ErrCanceledByUser = errors.New("Canceled by user")
func (self *handler) on_key_event(event *loop.KeyEvent) (err error) {
if event.MatchesPressOrRepeat("esc") || event.MatchesPressOrRepeat("ctrl+c") {
return ErrCanceledByUser
}
if event.MatchesPressOrRepeat("f1") || event.MatchesPressOrRepeat("ctrl+1") {
event.Handled = true
self.switch_mode(HEX)
} else if event.MatchesPressOrRepeat("f2") || event.MatchesPressOrRepeat("ctrl+2") {
event.Handled = true
self.switch_mode(NAME)
} else if event.MatchesPressOrRepeat("f3") || event.MatchesPressOrRepeat("ctrl+3") {
event.Handled = true
self.switch_mode(EMOTICONS)
} else if event.MatchesPressOrRepeat("f4") || event.MatchesPressOrRepeat("ctrl+4") {
event.Handled = true
self.switch_mode(FAVORITES)
} else if event.MatchesPressOrRepeat("ctrl+tab") || event.MatchesPressOrRepeat("ctrl+]") {View on GitHub (pinned to 6d5d0c4406)
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
Example fix
// before
if err := main(); err != nil { fmt.Fprintln(os.Stderr, err) } // prints 'Canceled by user'
// after
if err := main(); err != nil {
if !errors.Is(err, ErrCanceledByUser) {
fmt.Fprintln(os.Stderr, err)
}
os.Exit(1)
} Defensive patterns
Strategy: try-catch
Type guard
func isUserCancel(err error) bool {
return errors.Is(err, unicode_input.ErrCanceledByUser)
} Try / catch
if err := run(); err != nil {
if errors.Is(err, unicode_input.ErrCanceledByUser) {
return nil // clean cancel, no message
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Execute command
- No lexer available for this format
- No cache found and max cache age is negative
- This should be run as kitten unicode_input
- Too much piped data
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/90d40b78d83eed1f.
Report an issue: GitHub.