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
Original file line number Diff line number Diff line change
Expand Up @@ -420,17 +420,27 @@ def local_to_base64(local_file: str, mime_type: Optional[str]) -> str:
else:
# assume it's a file path
local_file = (match.group("link") or "").strip()
path = Path(local_file)
if not path.is_absolute():
path = working_dir / local_file
if not path.exists():
# The link could not be resolved to an existing local file. This can happen when markdown
# image syntax (e.g. ![alt](figures/1.1)) originates from Document Intelligence or similar
# services where the paths are relative references that are not actual files on disk.
# Treat the original markdown as plain text instead of crashing.
try:
path = Path(local_file)
if not path.is_absolute():
path = working_dir / local_file
if not path.exists():
Comment thread
YoYoJa marked this conversation as resolved.
# The link could not be resolved to an existing local file. This can happen when markdown
# image syntax (e.g. ![alt](figures/1.1)) originates from Document Intelligence or similar
# services where the paths are relative references that are not actual files on disk.
# Treat the original markdown as plain text instead of crashing.
logger.debug(
"Image reference '%s' could not be resolved to an existing file. Treating as plain text.",
image,
)
return {"type": "text", "text": image}
except (OSError, ValueError) as e:
# Path operations can fail when the filename exceeds OS limits (e.g., Linux 255-char name limit)
# or contains invalid characters. Treat as plain text rather than crashing.
logger.debug(
"Image reference '%s' could not be resolved to an existing file. Treating as plain text.",
"Image reference '%s' could not be resolved to a valid path (%s). Treating as plain text.",
image,
e,
)
return {"type": "text", "text": image}
inlined_uri = local_to_base64(local_file, mime_type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ def test_unparseable_markdown_image_returns_text(self, tmp_path):
assert result["type"] == "text"
assert result["text"] == '![alt](url "title")'

def test_filename_exceeds_os_limit_returns_text(self, tmp_path):
"""A filename exceeding the OS name limit (255 chars on Linux) should return text, not raise."""
long_name = "a" * 300 + ".png"
result = _inline_image(f"![alt]({long_name})", tmp_path, "auto")
assert result["type"] == "text"
assert result["text"] == f"![alt]({long_name})"

def test_path_with_null_byte_returns_text(self, tmp_path):
"""A path containing a null byte should return text, not raise."""
result = _inline_image("![alt](invalid\x00path.png)", tmp_path, "auto")
assert result["type"] == "text"
assert result["text"] == "![alt](invalid\x00path.png)"

def test_real_local_image_file(self, tmp_path):
"""A real local image file should still be base64-encoded as before."""
# Create a minimal valid PNG file (1x1 pixel)
Expand Down Expand Up @@ -125,6 +138,14 @@ def test_text_with_empty_alt_text_image(self, tmp_path):
for item in result:
assert item["type"] == "text"

def test_text_with_filename_exceeding_os_limit(self, tmp_path):
"""A filename exceeding OS limits in mixed content should become text, not crash."""
long_name = "b" * 300 + ".png"
result = _to_content_str_or_list(f"Text ![img]({long_name}) end", tmp_path, "auto")
assert isinstance(result, list)
for item in result:
assert item["type"] == "text"

def test_real_local_image_in_mixed_content(self, tmp_path):
"""Real local image file mixed with text should work as before."""
png_data = base64.b64decode(
Expand Down