oclif / oclif/plugin-not-found

command_not_found: accepting a suggestion for a command with a required arg leaks stack traces + a spurious "command not found"

Open
#1,132 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

BUG P3
Dominant language
TypeScript
Stars
17
Forks
10
Avg merge
24m
Merged PRs (30d)
2

Description

Describe the bug

When the command_not_found hook offers a "did you mean …?" suggestion and the user accepts, the hook re-runs the suggested command via this.config.runCommand(suggestion, argv) (src/index.ts). If that suggested command then fails a showHelp parse error (e.g. a missing required arg, RequiredArgsError, or an unexpected flag), the user is shown two raw stack traces instead of a clean error.

The root of the mis-render is in @oclif/core's top-level handle(), which renders showHelp-flagged errors with showHelp(process.argv.slice(2)). Because the failure surfaces from inside the hook, process.argv still holds the original, unknown command the user typed — not the suggested command that actually ran. showHelp can't resolve the original id, throws Command <typo> not found., and that lands in handle()'s emergency catch, which dumps err.stack followed by error.stack.

The same RequiredArgsError renders cleanly when the command is invoked directly, so the regression is specific to the suggestion-acceptance flow.

To Reproduce

A minimal CLI repro with a single command greet NAME (NAME required) and this plugin installed:

  1. Run repro gree (a typo of greet).
  2. At Warning: gree is not a repro command. Did you mean greet? [y/n], answer y.
  3. greet runs with no args and fails required-arg validation.
  4. Output (note the two stack traces + the spurious final line):
 ›   Warning: gree is not a repro command.
 ›   Error: Missing 1 required arg:
 ›   name  who to greet
 ›   See more help with --help

Error: Missing 1 required arg:
name  who to greet
See more help with --help
    at validateArgs (.../@oclif/core/lib/parser/validate.js:84:19)
    ...
    at async Config.runHook (.../@oclif/core/lib/config/config.js:524:9)
Error: Command gree not found.
    at error (.../@oclif/core/lib/errors/error.js:44:15)
    at Help.showHelp (.../@oclif/core/lib/help/index.js:269:27)
    at handle (.../@oclif/core/lib/errors/handle.js:46:28)

Contrast — running the suggested command directly, repro greet, produces the expected clean output (pretty error + USAGE/ARGUMENTS, no stack trace, no "not found").

Expected behavior

Accepting a suggestion should render the suggested command's parse error exactly as if it had been typed directly: the pretty message plus its usage/help, with no raw stack traces and no spurious "Command not found."

Environment (please complete the following information):

  • @oclif/plugin-not-found 3.2.93
  • @oclif/core 4.13.3
  • OS & version: macOS 15 (Darwin 25.4.0)
  • Shell/terminal & version: zsh
  • Node: v24.15.0

Additional context

The trigger is any showHelp-flagged parse error on the re-run: RequiredArgsError, UnexpectedArgsError, and NonExistentFlagsError all set showHelp = true. The underlying process.argv mismatch is in @oclif/core's handle() (showHelp(process.argv.slice(2)) vs. err.parse.input.argv), but it's only reachable in practice through this hook re-running a different command than the one the user typed. Two options: this plugin could catch/normalize the error from the re-run before it reaches handle(), and/or @oclif/core could render showHelp against err.parse.input.argv rather than process.argv.

I have a self-contained reproduction (fixture CLI + failing-vs-clean tests) and am happy to open a PR.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the self-contained fixture and failing-versus-clean tests, then inspect the suggestion re-run in src/index.ts and @oclif/core's top-level handle(). Reproduce the required-argument case and check the related unexpected-argument and nonexistent-flag cases. Done means accepted suggestions show the same clean parse error and help as direct invocation, without stack traces or a spurious command-not-found error.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
62/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.