Error Handling¶
BOA provides two execution modes: Run() for simple CLI apps, and RunE() for programmatic error handling.
Run() vs RunE()¶
| Method | Setup Errors | User Input Errors | Hook Errors | Runtime Errors |
|---|---|---|---|---|
Run() |
Panic | Exit(1) | Exit(1) | Panic |
RunE() |
Panic | Return | Return | Return |
RunArgs(args) |
Panic | Exit(1) | Exit(1) | Panic |
RunArgsE(args) |
Panic | Return | Return | Return |
Using Run()¶
Run() is the simplest way to execute a command. User input errors print a message and exit cleanly. See the table above for full behavior.
Using RunE()¶
RunE() returns all non-setup errors for programmatic handling. Ideal for testing, embedding, or custom error handling.
Error Types¶
BOA handles four categories of errors (see table above for behavior):
1. Setup Errors¶
Programming mistakes caught during command setup. Always panic.
- Invalid default value types (e.g.,
default:"abc"on anintfield) - Malformed struct tag syntax
- Unsupported field types
- Setting multiple run functions
- Positional argument ordering errors
2. User Input Errors¶
Invalid input from the CLI user. With Run(): prints error and exits(1). With RunE(): returns error.
- Missing required parameters
- Invalid flag values (e.g.,
--port abcfor an integer flag) - Unknown flags (e.g.,
--unknown-flag) - Invalid alternatives (enum validation failures)
- Custom validator failures
- Invalid environment variable values
- Missing positional arguments
type Params struct {
Name string `short:"n" required:"true"`
Mode string `default:"fast" alts:"fast,slow"`
}
// User runs: myapp --mode=invalid
// Output: Error: invalid value for param 'mode': 'invalid' is not in the list of allowed values: [fast slow]
// Exit code: 1
Creating User Input Errors in Hooks¶
Use NewUserInputError or NewUserInputErrorf to return user input errors from hooks:
Checking for User Input Errors¶
err := cmd.RunArgsE([]string{"--invalid-flag"})
if boa.IsUserInputError(err) {
// Handle user input error
}
3. Hook Errors¶
Errors from lifecycle hooks (Init, PostCreate, PreValidate, PreExecute). Behavior depends on Run() vs RunE() - see table.
4. Runtime Errors¶
Errors from your RunFuncE. Behavior depends on Run() vs RunE() - see table.
Error-Returning Run Functions¶
| Non-Error Variant | Error Variant | Description |
|---|---|---|
RunFunc |
RunFuncE |
Basic run function |
RunFuncCtx |
RunFuncCtxE |
Run function with HookContext access |
ToCobra() vs ToCobraE()¶
| Method | Returns | Setup Errors | Hook Errors |
|---|---|---|---|
ToCobra() |
*cobra.Command |
Panic | Panic |
ToCobraE() |
(*cobra.Command, error) |
Panic | Return |
Testing¶
Use RunE() and RunArgsE() for testing:
func TestMyCommand_InvalidPort(t *testing.T) {
err := boa.CmdT[Params]{
Use: "app",
RunFuncE: func(p *Params, cmd *cobra.Command, args []string) error {
if p.Port < 1024 {
return fmt.Errorf("port must be >= 1024")
}
return nil
},
}.RunArgsE([]string{"--port", "80"})
if err == nil {
t.Fatal("expected error for port < 1024")
}
}
Only One Run Function¶
You can only set one run function per command. Setting multiple causes a setup error (panic):