Skip to content

--json output mode is guessed via naive argv scanning, allowing prose+JSON to both land on stdout #139

Description

@codeforester

Summary

Before Click parses arguments, run_app() decides whether to buffer stdout for JSON-envelope wrapping using a naive scan for the literal token --json in argv — which diverges from Click's actual parse result.

Details

  • lib/python/base_cli/app.py:2971 (_json_requested) just checks whether a literal "--json" token appears anywhere in args, consumed at :2859 and :2872.
  • The correct value is only known later, via _capture_standard_options (:306).
  • This diverges from Click's real parsing whenever --json is set through anything other than an exact literal token: a Click default_map (a standard Click feature), or a combined short-flag form like -xj (meaning -x -j, standard Click flag-combining). Both were reproduced directly.
  • The same heuristic-scanning weakness also exists in _leading_output_flags/_lifecycle_flag_declarations (:3121/:3089) for early debug/quiet detection — lower impact there since it only affects diagnostic verbosity before real option parsing completes.

Impact

When JSON is actually requested via default_map or a combined short flag, the command's own print() output goes to raw stdout (never captured) while run_app() still appends a JSON envelope afterward — producing stdout that is prose followed by JSON. This directly violates the documented contract in docs/json-contracts.md ("exactly one success or error envelope on stdout... cannot introduce prose... as a second stdout record") and breaks any automation parsing stdout as JSON.

Suggested fix

Don't pre-decide based on raw argv; always capture stdout into a buffer for commands whose LifecycleOptions.json is configured (the cost is negligible), and make the final "wrap or not" decision solely from the Click-parsed value already captured in _capture_standard_options.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething is not working

Type

No type

Projects

  • Status
    Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions