diff --git a/haystack/components/converters/json.py b/haystack/components/converters/json.py index 08df7d7271b..9dd79bd3314 100644 --- a/haystack/components/converters/json.py +++ b/haystack/components/converters/json.py @@ -211,7 +211,15 @@ def _get_content_and_meta(self, source: ByteStream) -> list[tuple[str, dict[str, else: # We just load the whole file as JSON if the user didn't provide a jq filter. # We put it in a list even if it's not to ease handling it later on. - objects = [json.loads(file_content)] + try: + objects = [json.loads(file_content)] + except json.JSONDecodeError as exc: + logger.warning( + "Failed to extract text from {source}. Skipping it. Error: {error}", + source=source.meta["file_path"], + error=exc, + ) + return [] result = [] if self._content_key is not None: diff --git a/releasenotes/notes/fix-json-converter-content-key-malformed-8a7abe0d43e5355c.yaml b/releasenotes/notes/fix-json-converter-content-key-malformed-8a7abe0d43e5355c.yaml new file mode 100644 index 00000000000..05377f520cb --- /dev/null +++ b/releasenotes/notes/fix-json-converter-content-key-malformed-8a7abe0d43e5355c.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed ``JSONConverter`` crashing on a malformed JSON source when it is + configured with ``content_key`` and no ``jq_schema``. The non-jq branch + called ``json.loads`` without a guard, so a single invalid ``.json`` file + raised an unhandled ``JSONDecodeError`` and aborted the whole run. Invalid + JSON is now caught, logged, and skipped, matching the behavior of the + ``jq_schema`` path. diff --git a/test/components/converters/test_json.py b/test/components/converters/test_json.py index 9262964ac0d..3d55a89eb14 100644 --- a/test/components/converters/test_json.py +++ b/test/components/converters/test_json.py @@ -258,6 +258,23 @@ def test_run_with_bad_encoding(tmpdir, caplog): assert result == {"documents": []} +def test_run_with_malformed_json_and_content_key(tmpdir, caplog): + test_file = Path(tmpdir / "test_file.json") + test_file.write_text("This is not valid JSON.", "utf-8") + + sources = [test_file] + converter = JSONConverter(content_key="motivation") + + caplog.clear() + with caplog.at_level(logging.WARNING): + result = converter.run(sources=sources) + + records = caplog.records + assert len(records) == 1 + assert records[0].msg.startswith(f"Failed to extract text from {test_file}. Skipping it. Error:") + assert result == {"documents": []} + + def test_run_with_single_meta(tmpdir): first_test_file = Path(tmpdir / "first_test_file.json") second_test_file = Path(tmpdir / "second_test_file.json")