[GH-ISSUE #518] Exit code parity: usage validation errors should return ExitUsage (2) consistently #142

Closed
opened 2026-02-26 21:33:45 +03:00 by kerem · 3 comments
Owner

Originally created by @rudrankriyam on GitHub (Feb 14, 2026).
Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/518

Summary

A set of command-level validation failures return generic errors (fmt.Errorf) rather than usage errors (flag.ErrHelp), which causes process exit code 1 instead of 2.

Why this matters

Automation relies on stable exit code contracts. Invalid invocation/flags should map to usage exit code (2), not generic runtime error (1).

Current behavior

cmd/exit_codes.go maps usage errors only when errors.Is(err, flag.ErrHelp).
Several commands return fmt.Errorf(...) for mutual-exclusion and invalid-flag usage cases.

Representative examples:

  • internal/cli/submit/submit.go
  • internal/cli/auth/auth.go
  • internal/cli/apps/app_info.go
  • internal/cli/performance/performance_download.go
  • internal/cli/xcodecloud/xcode_cloud.go
  • internal/cli/publish/publish.go

Reproduction

Example:

asc submit create --version "1.0" --version-id "V123" --build "B1" --confirm

Current outcome: validation failure exits with code 1.
Expected: exit code 2 for usage error.

Expected behavior

Invalid CLI usage (missing required flags, incompatible flag combinations, invalid flag value semantics) should return usage-class errors and exit 2 consistently.

Detailed implementation plan

  • Define/standardize validation error strategy for CLI commands:
    • prefer printing clear error to stderr + returning flag.ErrHelp, or
    • use a dedicated typed usage error that maps to ExitUsage.
  • Update commands currently returning fmt.Errorf for usage-only failures.
  • Add regression tests covering representative commands and edge cases.
  • Ensure black-box exit code behavior is verified for known invalid invocations.

Acceptance criteria

  • Invalid usage cases consistently return exit code 2.
  • Runtime/API failures continue to return non-usage error codes.
  • Existing success-path behavior/output remains unchanged.

cc @cursor please implement this end-to-end.

Originally created by @rudrankriyam on GitHub (Feb 14, 2026). Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/518 ## Summary A set of command-level validation failures return generic errors (`fmt.Errorf`) rather than usage errors (`flag.ErrHelp`), which causes process exit code `1` instead of `2`. ## Why this matters Automation relies on stable exit code contracts. Invalid invocation/flags should map to usage exit code (`2`), not generic runtime error (`1`). ## Current behavior `cmd/exit_codes.go` maps usage errors only when `errors.Is(err, flag.ErrHelp)`. Several commands return `fmt.Errorf(...)` for mutual-exclusion and invalid-flag usage cases. Representative examples: - `internal/cli/submit/submit.go` - `internal/cli/auth/auth.go` - `internal/cli/apps/app_info.go` - `internal/cli/performance/performance_download.go` - `internal/cli/xcodecloud/xcode_cloud.go` - `internal/cli/publish/publish.go` ## Reproduction Example: ```bash asc submit create --version "1.0" --version-id "V123" --build "B1" --confirm ``` Current outcome: validation failure exits with code `1`. Expected: exit code `2` for usage error. ## Expected behavior Invalid CLI usage (missing required flags, incompatible flag combinations, invalid flag value semantics) should return usage-class errors and exit `2` consistently. ## Detailed implementation plan - [ ] Define/standardize validation error strategy for CLI commands: - prefer printing clear error to stderr + returning `flag.ErrHelp`, or - use a dedicated typed usage error that maps to `ExitUsage`. - [ ] Update commands currently returning `fmt.Errorf` for usage-only failures. - [ ] Add regression tests covering representative commands and edge cases. - [ ] Ensure black-box exit code behavior is verified for known invalid invocations. ## Acceptance criteria - [ ] Invalid usage cases consistently return exit code `2`. - [ ] Runtime/API failures continue to return non-usage error codes. - [ ] Existing success-path behavior/output remains unchanged. cc @cursor please implement this end-to-end.
kerem 2026-02-26 21:33:45 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@rudrankriyam commented on GitHub (Feb 14, 2026):

@cursor please implement this issue end-to-end using the checklist and acceptance criteria.

<!-- gh-comment-id:3900361498 --> @rudrankriyam commented on GitHub (Feb 14, 2026): @cursor please implement this issue end-to-end using the checklist and acceptance criteria.
Author
Owner

@cursor[bot] commented on GitHub (Feb 14, 2026):

Implemented end-to-end on cursor/exit-code-parity-c50a and pushed. I standardized usage-validation handling by adding shared.UsageError/UsageErrorf (internal/cli/shared/errors.go) and updating the requested command paths to print a clear stderr message and return flag.ErrHelp for invalid usage semantics. I applied this to the representative files from the PR: submit.go, auth.go, app_info.go, performance_download.go, xcode_cloud.go, and publish.go (mutual-exclusion checks, invalid value semantics like limit/timeout/poll/platform/output constraints, etc.), while leaving runtime/API failure paths as normal non-usage errors.

I also updated/expanded regression coverage (TDD style) across internal/cli/submit/submit_test.go, internal/cli/auth/auth_test.go, and cmd-level suites in internal/cli/cmdtest (including explicit exit-code parity assertions in exit_codes_test.go). Validation run results:

  • Targeted parity tests: pass (submit, auth, and relevant cmdtest suites).
  • Full required checks: make format, make lint, make test all pass.
  • Black-box binary checks (go build -o /tmp/asc .) confirmed exit code 2 for representative invalid invocations:
    • submit create conflicting --version/--version-id
    • app-info get conflicting --version/--version-id
    • performance download conflicting selectors
    • xcode-cloud run conflicting workflow flags
    • publish appstore invalid --timeout

I made and pushed 4 commits:

  • 3954c79 test: require usage-class validation errors
  • 9616241 fix: map CLI validation failures to usage errors
  • 615e175 test: stabilize auth usage parity exit-code case
  • 849464d test: align cmdtest usage-validation expectations
    I also added a walkthrough artifact with the black-box exit-code evidence at: /opt/cursor/artifacts/exit_code_parity_blackbox.txt.

View PR

Open in Cursor Open in Web

<!-- gh-comment-id:3900361629 --> @cursor[bot] commented on GitHub (Feb 14, 2026): Implemented end-to-end on `cursor/exit-code-parity-c50a` and pushed. I standardized usage-validation handling by adding `shared.UsageError/UsageErrorf` (`internal/cli/shared/errors.go`) and updating the requested command paths to print a clear stderr message and return `flag.ErrHelp` for invalid usage semantics. I applied this to the representative files from the PR: `submit.go`, `auth.go`, `app_info.go`, `performance_download.go`, `xcode_cloud.go`, and `publish.go` (mutual-exclusion checks, invalid value semantics like limit/timeout/poll/platform/output constraints, etc.), while leaving runtime/API failure paths as normal non-usage errors. I also updated/expanded regression coverage (TDD style) across `internal/cli/submit/submit_test.go`, `internal/cli/auth/auth_test.go`, and cmd-level suites in `internal/cli/cmdtest` (including explicit exit-code parity assertions in `exit_codes_test.go`). Validation run results: - Targeted parity tests: pass (`submit`, `auth`, and relevant `cmdtest` suites). - Full required checks: `make format`, `make lint`, `make test` all pass. - Black-box binary checks (`go build -o /tmp/asc .`) confirmed exit code `2` for representative invalid invocations: - `submit create` conflicting `--version/--version-id` - `app-info get` conflicting `--version/--version-id` - `performance download` conflicting selectors - `xcode-cloud run` conflicting workflow flags - `publish appstore` invalid `--timeout` I made and pushed 4 commits: - `3954c79` test: require usage-class validation errors - `9616241` fix: map CLI validation failures to usage errors - `615e175` test: stabilize auth usage parity exit-code case - `849464d` test: align cmdtest usage-validation expectations I also added a walkthrough artifact with the black-box exit-code evidence at: `/opt/cursor/artifacts/exit_code_parity_blackbox.txt`. <p><a href="https://github.com/rudrankriyam/App-Store-Connect-CLI/pull/534"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/view-pr-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/view-pr-light.png"><img alt="View PR" width="86" height="28" src="https://cursor.com/assets/images/view-pr-light.png"></picture></a></p> <p><a href="https://cursor.com/background-agent?bcId=bc-83da15c9-b1b9-4fab-a2c4-ccd55ce8f817"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/agents?id=bc-83da15c9-b1b9-4fab-a2c4-ccd55ce8f817"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a></p>
Author
Owner

@rudrankriyam commented on GitHub (Feb 14, 2026):

Fixed in #534 (merged to main).

<!-- gh-comment-id:3900688788 --> @rudrankriyam commented on GitHub (Feb 14, 2026): Fixed in #534 (merged to main).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/App-Store-Connect-CLI#142
No description provided.