Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/markitdown/src/markitdown/converters/_exiftool.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def exiftool_metadata(
f"ExifTool version {version_output} is vulnerable to CVE-2021-22204. "
"Please upgrade to version 12.24 or later."
)
except (subprocess.CalledProcessError, ValueError) as e:
raise RuntimeError("Failed to verify ExifTool version.") from e
except (subprocess.CalledProcessError, ValueError, OSError) as e:
raise RuntimeError(f"Failed to invoke exiftool at {exiftool_path}: {e}") from e

# Run exiftool
cur_pos = file_stream.tell()
Expand All @@ -48,5 +48,7 @@ def exiftool_metadata(
return json.loads(
output.decode(locale.getpreferredencoding(False)),
)[0]
except OSError as e:
raise RuntimeError(f"Failed to invoke exiftool at {exiftool_path}: {e}") from e
finally:
file_stream.seek(cur_pos)
23 changes: 23 additions & 0 deletions packages/markitdown/tests/test_module_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,3 +552,26 @@ def test_markitdown_llm() -> None:
test()
print("OK")
print("All tests passed!")


# ---------------------------------------------------------------------------
# Regression test for issue #1960:
# exiftool_path pointing to a nonexistent binary used to leak a raw
# FileNotFoundError. It should now be wrapped in RuntimeError with a
# message that includes the path.
# ---------------------------------------------------------------------------


def test_exiftool_metadata_with_nonexistent_binary():
"""#1960: nonexistent exiftool_path raises RuntimeError, not FileNotFoundError."""
from markitdown.converters._exiftool import exiftool_metadata

with pytest.raises(RuntimeError, match="Failed to invoke exiftool"):
exiftool_metadata(io.BytesIO(b""), exiftool_path="/this/does/not/exist/exiftool")


def test_exiftool_metadata_with_no_path():
"""Sanity check: exiftool_path=None still returns {} (early return)."""
from markitdown.converters._exiftool import exiftool_metadata

assert exiftool_metadata(io.BytesIO(b""), exiftool_path=None) == {}