diff --git a/app.go b/app.go index 9c7f679..a17300d 100644 --- a/app.go +++ b/app.go @@ -8,6 +8,7 @@ import ( "path/filepath" "reflect" "sort" + "strings" "time" ) @@ -464,11 +465,13 @@ func (a Author) String() string { func HandleAction(action interface{}, context *Context) (err error) { defer func() { if r := recover(); r != nil { - switch r.(type) { - case error: - err = r.(error) - default: - err = NewExitError(fmt.Sprintf("ERROR unknown Action error: %v. See %s", r, appActionDeprecationURL), 2) + // Try to detect a known reflection error from *this scope*, rather than + // swallowing all panics that may happen when calling an Action func. + s := fmt.Sprintf("%v", r) + if strings.HasPrefix(s, "reflect: ") && strings.Contains(s, "too many input arguments") { + err = NewExitError(fmt.Sprintf("ERROR unknown Action error: %v. See %s", r, appActionDeprecationURL), 2) + } else { + panic(r) } } }() diff --git a/app_test.go b/app_test.go index 42c852e..ee8cc35 100644 --- a/app_test.go +++ b/app_test.go @@ -1452,3 +1452,16 @@ func TestHandleAction_WithInvalidFuncReturnSignature(t *testing.T) { t.Fatalf("expected error exit code to be 2, but got: %v", exitErr.ExitCode()) } } + +func TestHandleAction_WithUnknownPanic(t *testing.T) { + defer func() { refute(t, recover(), nil) }() + + var fn ActionFunc + + app := NewApp() + app.Action = func(ctx *Context) error { + fn(ctx) + return nil + } + HandleAction(app.Action, NewContext(app, flagSet(app.Name, app.Flags), nil)) +}