Bug
When a command has required path parameters (like cluster info's --target) but the user provides no input at all (no CLI flags, no stdin, no --input-file), the handler runs with parsed.input as undefined. The Zod validation step is skipped entirely, and the required {param} placeholder remains as a literal string in the URL sent to Elasticsearch.
Steps to reproduce
$ elastic es cluster info
Expected: Error message indicating --target is required.
Actual:
{
"error": {
"code": "transport_error",
"status_code": 400,
"body": {
"error": {
"type": "illegal_argument_exception",
"reason": "request [/_info/{target}] contains unrecognized target: [{target}]"
}
}
}
}
The literal {target} is sent in the URL path.
Root cause
src/factory.ts, in the cmd.action() handler:
- Schema-derived args are registered with
cmd.option() (optional), never cmd.requiredOption()
- When no input is provided at all,
inputValue remains undefined
- The validation block (
if (inputValue !== undefined) { ... safeParse ... }) is skipped
parsed.input stays undefined, and the handler runs
interpolatePath() in the request builder can't substitute {target} because input is undefined, and arg.required is true so the optional-path-stripping branch doesn't apply
Suggested fix
Options:
- Register required schema args with
cmd.requiredOption() instead of cmd.option() so Commander enforces them before the handler runs
- Run Zod validation even when
inputValue is undefined: construct a minimal input from CLI args (even if empty) and validate it to catch missing required fields
- In
interpolatePath(), check for unresolved {param} placeholders after interpolation and throw a clear error
Option 2 is probably the most robust since it catches required body/query fields too, not just path params.
Bug
When a command has required path parameters (like
cluster info's--target) but the user provides no input at all (no CLI flags, no stdin, no--input-file), the handler runs withparsed.inputasundefined. The Zod validation step is skipped entirely, and the required{param}placeholder remains as a literal string in the URL sent to Elasticsearch.Steps to reproduce
Expected: Error message indicating
--targetis required.Actual:
{ "error": { "code": "transport_error", "status_code": 400, "body": { "error": { "type": "illegal_argument_exception", "reason": "request [/_info/{target}] contains unrecognized target: [{target}]" } } } }The literal
{target}is sent in the URL path.Root cause
src/factory.ts, in thecmd.action()handler:cmd.option()(optional), nevercmd.requiredOption()inputValueremainsundefinedif (inputValue !== undefined) { ... safeParse ... }) is skippedparsed.inputstaysundefined, and the handler runsinterpolatePath()in the request builder can't substitute{target}because input is undefined, andarg.requiredis true so the optional-path-stripping branch doesn't applySuggested fix
Options:
cmd.requiredOption()instead ofcmd.option()so Commander enforces them before the handler runsinputValueis undefined: construct a minimal input from CLI args (even if empty) and validate it to catch missing required fieldsinterpolatePath(), check for unresolved{param}placeholders after interpolation and throw a clear errorOption 2 is probably the most robust since it catches required body/query fields too, not just path params.