From f401b660c8a5a5293d0c7b12acb84138f989180f Mon Sep 17 00:00:00 2001 From: seven7763 Date: Fri, 4 Sep 2026 08:21:51 +0800 Subject: [PATCH] Report invalid --format-options as a CLI error, not a traceback An invalid --format-options value (bad type, unknown key, bare section) escaped parse_format_options() as an unhandled argparse.ArgumentTypeError and crashed with a traceback. Catch it in _process_format_options() and route it through self.error() so it is reported like every other CLI error. Fixes #1938 --- httpie/cli/argparser.py | 7 +++++-- tests/test_output.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 9bf09b3b73..3b86f6ec96 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -554,8 +554,11 @@ def _process_download_options(self): def _process_format_options(self): format_options = self.args.format_options or [] parsed_options = PARSED_DEFAULT_FORMAT_OPTIONS - for options_group in format_options: - parsed_options = parse_format_options(options_group, defaults=parsed_options) + try: + for options_group in format_options: + parsed_options = parse_format_options(options_group, defaults=parsed_options) + except argparse.ArgumentTypeError as ex: + self.error(str(ex)) self.args.format_options = parsed_options def print_manual(self): diff --git a/tests/test_output.py b/tests/test_output.py index 2242177dbc..8841dd5935 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -598,6 +598,27 @@ def test_format_options_accumulation(self, args, expected_format_options): ) assert parsed_args.format_options == expected_format_options + @pytest.mark.parametrize( + 'options, expected_error', + [ + ('json.indent:x', "invalid value 'x' in 'json.indent:x' (expected int got str)"), + ('json.nope:1', "invalid key 'json.nope'"), + ('json', "invalid option 'json'"), + ] + ) + def test_invalid_format_options_reported_as_cli_error( + self, options, expected_error + ): + r = http( + '--offline', + '--format-options', options, + 'example.org', + tolerate_error_exit_status=True, + ) + assert r.exit_status == ExitStatus.ERROR + assert expected_error in r.stderr + assert 'Traceback' not in r.stderr + @responses.activate def test_response_mime_overwrite():