Summary
For operations with more than one path parameter, the generated command lists (and consumes) its positional arguments in the order they appear in the spec's parameters array, rather than the order the {placeholders} appear in the URL path. When a spec lists those params in a different order than the path (which OpenAPI permits — array order is not significant), the CLI's positional arg order is reversed relative to the path. Users who pass args in the natural path order silently hit the wrong resource (or a 404).
Example
Route: GET /api/v2/documents/{identifier}/draft/{draftIdentifier}
Generated usage:
omni documents v2-get-draft <draftidentifier> <identifier>
The path has {identifier} first, but the command asks for <draftidentifier> first.
# Natural call — args in path order (document, then draft):
omni documents v2-get-draft <doc-id> <draft-id>
# -> 404: substitutes {draftIdentifier}=<doc-id>, {identifier}=<draft-id>
# Only works if you invert to match the printed (reversed) usage:
omni documents v2-get-draft <draft-id> <doc-id> # works
Same reversal affects documents v2-patch-draft-by-identifier — and there it's higher-risk: if both ids happen to be valid documents, a PATCH could mutate the wrong document with no error.
Root cause
- Usage string is built from
op.PathParams in spec-array order — internal/openapi/generate.go (~L163).
cobra.ExactArgs + substitution then consume args in that same array order (~L186).
- Substitution itself is correct (by-name), so following the printed (reversed) usage works — but the order contradicts the path, which is the trap.
Per OpenAPI, parameters array order carries no meaning; path params must be resolved by name/position-in-path. The generator shouldn't depend on array order.
Suggested fix
Order op.PathParams by the index of each {name} within op.Path before building the usage string and the substitution loop. Sketch:
sort.SliceStable(op.PathParams, func(i, j int) bool {
return strings.Index(op.Path, "{"+op.PathParams[i].Name+"}") <
strings.Index(op.Path, "{"+op.PathParams[j].Name+"}")
})
This makes both the usage and the request robust regardless of how the spec orders its parameters array. (Single-path-param commands — the vast majority — are unaffected.)
Repro environment
Found while smoke-testing a from-source build against the v2 documents routes; confirmed v2-get-draft returns the correct draft only when args are passed in the reversed (printed) order.
Filed by Claude on behalf of @barberscott.
Summary
For operations with more than one path parameter, the generated command lists (and consumes) its positional arguments in the order they appear in the spec's
parametersarray, rather than the order the{placeholders}appear in the URL path. When a spec lists those params in a different order than the path (which OpenAPI permits — array order is not significant), the CLI's positional arg order is reversed relative to the path. Users who pass args in the natural path order silently hit the wrong resource (or a 404).Example
Route:
GET /api/v2/documents/{identifier}/draft/{draftIdentifier}Generated usage:
The path has
{identifier}first, but the command asks for<draftidentifier>first.Same reversal affects
documents v2-patch-draft-by-identifier— and there it's higher-risk: if both ids happen to be valid documents, a PATCH could mutate the wrong document with no error.Root cause
op.PathParamsin spec-array order —internal/openapi/generate.go(~L163).cobra.ExactArgs+ substitution then consume args in that same array order (~L186).Per OpenAPI,
parametersarray order carries no meaning; path params must be resolved by name/position-in-path. The generator shouldn't depend on array order.Suggested fix
Order
op.PathParamsby the index of each{name}withinop.Pathbefore building the usage string and the substitution loop. Sketch:This makes both the usage and the request robust regardless of how the spec orders its
parametersarray. (Single-path-param commands — the vast majority — are unaffected.)Repro environment
Found while smoke-testing a from-source build against the v2 documents routes; confirmed
v2-get-draftreturns the correct draft only when args are passed in the reversed (printed) order.Filed by Claude on behalf of @barberscott.