Skip to content

fix: exit non-zero on unknown subcommand of grouping parents#346

Merged
gtsiolis merged 2 commits into
mainfrom
devx-941-lstk-exits-with-code-0-on-failure-50a1
Jun 30, 2026
Merged

fix: exit non-zero on unknown subcommand of grouping parents#346
gtsiolis merged 2 commits into
mainfrom
devx-941-lstk-exits-with-code-0-on-failure-50a1

Conversation

@gtsiolis

@gtsiolis gtsiolis commented Jun 29, 2026

Copy link
Copy Markdown
Member

Parent commands that only group subcommands (config, setup, volume, snapshot) had no RunE, so Cobra printed help and exited 0 for an unknown or missing subcommand — e.g. lstk config bogus and lstk setup bogus reported success despite being invalid usage. Unknown top-level commands and unknown flags already exited non-zero; the bug was specific to subcommands of these non-runnable grouping parents.

The fix adds a requireSubcommand helper (cmd/root.go) that sets cobra.NoArgs plus a help-printing RunE on these parents. Cobra skips arg validation on a non-runnable parent, so the RunE is the load-bearing part — it makes the command runnable so NoArgs actually rejects the stray subcommand. A bare invocation (lstk config) still prints help and exits 0, while an unknown subcommand now exits 1 with Error: unknown command "bogus" for "lstk config" on stderr.

Cobra's autogenerated completion command is the same shape — a non-runnable parent grouping bash/zsh/fish/powershell — so lstk completion bogus had the identical exit-0 bug. Since that command is created lazily, lstk now materializes it (InitDefaultCompletionCmd) and applies requireSubcommand to it as well.

The issue's literal example (lstk start --bogus-flag-xyz, an unknown flag) already exited non-zero; the regression test covers it alongside the parent-command cases to lock the behavior down.

Verified manually and with integration tests in test/integration/exit_code_test.go: unknown flag, unknown command, and an unknown subcommand of every grouping parent (config/setup/volume/snapshot/completion) → exit 1; bare parent → exit 0.

Note

A sibling exit-0 bug found while investigating this — lstk setup aws exiting 0 when it can't write the profile — is split out to #349 (DEVX-944) to keep this PR focused on invalid-usage exit codes. The npm-launcher half of the report (the wrapper swallowing the binary's exit code) is handled separately in #347 (DEVX-942).

@gtsiolis gtsiolis marked this pull request as ready for review June 29, 2026 21:49
@gtsiolis gtsiolis requested a review from a team as a code owner June 29, 2026 21:49
@anisaoshafi anisaoshafi added semver: patch docs: skip Pull request does not require documentation changes labels Jun 30, 2026
Parent commands that only group subcommands (config, setup, volume,
snapshot) had no RunE, so Cobra printed help and exited 0 for an unknown
or missing subcommand (e.g. `lstk config bogus`). This made lstk report
success on an invalid invocation.

Add a requireSubcommand helper that sets cobra.NoArgs plus a
help-printing RunE so a bare parent invocation still shows help (exit 0)
while an unknown subcommand exits non-zero. Add integration tests
covering both the new behavior and the unknown-flag/unknown-command
cases.

Generated with [Linear](https://linear.app/localstack/issue/DEVX-941/lstk-exits-with-code-0-on-failure#agent-session-0d671de0)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@gtsiolis gtsiolis self-assigned this Jun 30, 2026
@gtsiolis gtsiolis force-pushed the devx-941-lstk-exits-with-code-0-on-failure-50a1 branch from 8bce2d1 to ebd0abb Compare June 30, 2026 08:45
@gtsiolis gtsiolis changed the title fix: exit non-zero on unknown subcommand of grouping parents fix: exit non-zero on invalid usage and failed AWS profile setup Jun 30, 2026
@gtsiolis gtsiolis force-pushed the devx-941-lstk-exits-with-code-0-on-failure-50a1 branch from ebd0abb to d65c10e Compare June 30, 2026 08:54
@gtsiolis gtsiolis changed the title fix: exit non-zero on invalid usage and failed AWS profile setup fix: exit non-zero on unknown subcommand of grouping parents Jun 30, 2026
Cobra's autogenerated `completion` command is itself a subcommand-grouping
parent (bash/zsh/fish/powershell) with no RunE, so an unknown shell such as
`lstk completion bogus` hit the same exit-0 path as the other grouping
parents: it printed help and exited 0. Unlike config/setup/volume/snapshot,
the completion command is created lazily during Execute, so materialize it
via InitDefaultCompletionCmd() before applying requireSubcommand.

Covers the `completion bogusshell` case from the original report and adds it
to the exit-code regression tests.

@anisaoshafi anisaoshafi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this 👏🏼 makes sense!

@gtsiolis gtsiolis merged commit 0a8501d into main Jun 30, 2026
13 checks passed
@gtsiolis gtsiolis deleted the devx-941-lstk-exits-with-code-0-on-failure-50a1 branch June 30, 2026 15:54
peter-smith-phd added a commit that referenced this pull request Jun 30, 2026
…rrors to stderr

Telemetry (incorporates PR feedback): extension invocations now reach the
analytics pipeline / data warehouse, not just the OTel tracing exporter.
dispatchExtension emits an `lstk_command` event named `ext:<name>` (duration +
exit code) for a resolved extension, so the warehouse tracks which extension
ran. instrumentCommands skips its generic emit for the extension-dispatch path
so the run is no longer mislabeled as `start`, and an unresolved command records
nothing. extension.Invoke keeps its OTel span for tracing.

CI fixes (failures after merging main #346):
- The unknown-command error now goes to stderr (matching Cobra's own output),
  so `lstk <unknown>` puts "unknown command" on stderr and exits 1 — fixes
  TestInvalidUsageExitsNonZero/unknown_command and the in-tree
  TestExtensionUnknownCommandNoExtensionErrors.
- The self-authorization integration tests strip the inherited
  LOCALSTACK_AUTH_TOKEN (CI sets one) so the "without token" path truly conveys
  no token and the extension refuses (exit 13).
- Add TestExtensionInvocationRecordedInTelemetry asserting the `ext:<name>`
  event (and that it is not labeled `start`).

Updates design Decision 8, the extension-runtime-context telemetry requirement,
and task 3.6 to distinguish product telemetry (warehouse) from OTel tracing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs: skip Pull request does not require documentation changes semver: patch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants