Skip to content

HandleExitCoder does not see an ExitCoder wrapped with %w #2478

Closed

Description

@PerryLink

What happened

HandleExitCoder looks for an ExitCoder (and for a MultiError) with a bare type assertion, so an exit error that has been wrapped with fmt.Errorf("%w") is not recognised. Nothing calls OsExiter and nothing is written to ErrWriter; the process then exits with the default code 1.

cmd.Action = func(ctx context.Context, cmd *cli.Command) error {
    return fmt.Errorf("deploy failed: %w", cli.Exit("galactic perimeter breach", 9))
}

Running that command prints nothing, and the exit code is 1 instead of 9.

Why it matters

Exit documents that the underlying error stays reachable through the standard wrapping helpers, and exitError implements Unwrap() (that is what #1090 and #2444 added). Adding context to an Action error with %w is the ordinary way to do it, and the only consumer of that promise — HandleExitCoder — did not follow.

The same happens inside a MultiError: the last exit code is read with a bare assertion, so newMultiError(errors.New("wowsa"), fmt.Errorf("...: %w", Exit("boom", 11))) exits with 1 instead of 11.

Expected

A wrapped ExitCoder should be handled exactly like an unwrapped one: the message goes to ErrWriter, OsExiter is called, and the exit code is preserved.

Environment

urfave/cli v3 (main), Go 1.27.1 on Windows. Reproduced on 2026-10-19.

Activity

  1. added a commit that references this issue on Oct 21, 2026
    851da03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions