urfave/cli · info · exitError
%+v
Error message
%+v
What it means
cli.Exit builds an ExitCoder from a message and code. When the message is neither an error nor an ErrorFormatter, it is formatted with fmt.Errorf("%+v", message), so the resulting error's text is the %+v rendering of whatever was passed (e.g. a struct dump).
Source
Thrown at errors.go:134
type exitError struct {
exitCode int
err error
}
// Exit wraps a message and exit code into an error, which by default is
// handled with a call to os.Exit during default error handling.
//
// This is the simplest way to trigger a non-zero exit code for a Command without
// having to call os.Exit manually. During testing, this behavior can be avoided
// by overriding the ExitErrHandler function on a Command or the package-global
// OsExiter function.
func Exit(message any, exitCode int) ExitCoder {
var err error
switch e := message.(type) {
case ErrorFormatter:
err = fmt.Errorf("%+v", message)
case error:
err = e
default:
err = fmt.Errorf("%+v", message)
}
return &exitError{
err: err,
exitCode: exitCode,
}
}
func (ee *exitError) Error() string {
return ee.err.Error()
}
func (ee *exitError) ExitCode() int {
return ee.exitCodeView on GitHub (pinned to 1a4deb4f5a)
Solutions
- Pass a string or errors.New(...) as the message
- If passing structured data, format it first with fmt.Sprintf("%v", data)
- Implement the ErrorFormatter interface so %+v yields a readable message
Example fix
// before
return cli.Exit(myStruct, 1)
// after
return cli.Exit(fmt.Sprintf("invalid input: %v", myStruct), 1) Defensive patterns
Strategy: type-guard
Type guard
func exitMsg(v any) error {
switch m := v.(type) {
case error:
return m
case fmt.Stringer:
return errors.New(m.String())
default:
return errors.New(fmt.Sprint(v))
}
} Try / catch
err := cli.Exit(msg, 1)
// inspect what will be printed before exiting
if !isUserReadable(fmt.Sprint(msg)) { msg = fmt.Sprintf("exit: %v", msg) } Prevention
- Only pass string or error values to cli.Exit
- Implement ErrorFormatter/Stringer for structured message types
- Unit-test the rendered message of exit errors
When it happens
Trigger: Calling cli.Exit with a non-error, non-ErrorFormatter value such as a struct, slice, or map; the message text is then '%+v' output rather than a human-readable string.
Common situations: Passing raw data structures to Exit instead of formatting them first; assuming Exit takes a string; refactors that change a string argument to a typed value.
Related errors
- invalid value %q for argument %s: %v
- args %s has max 0, not parsing argument
- args %s has min[%d] > max[%d], not parsing argument
- sufficient count of arg %s not provided, given %d expected %
- invalid value %q for flag -%s: %v
AI-assisted analysis of urfave/cli@1a4deb4f5a (2026-08-31).
Data as JSON: /api/errors/c4b1149e698bd873.
Report an issue: GitHub.