Skip to content

[Bugfix] properly catch PIL-related errors for vision models when incorrect data urls are provided #19202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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
13 changes: 13 additions & 0 deletions tests/multimodal/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ async def test_fetch_image_local_files(image_url: str):
f"file://{temp_dir}/../{os.path.basename(image_url)}")


@pytest.mark.asyncio
async def test_fetch_image_error_conversion():
connector = MediaConnector()
broken_img = "data:image/png;base64,aGVsbG9fdmxsbV9jb21tdW5pdHkK"

# PIL.UnidentifiedImageError should be converted to ValueError
with pytest.raises(ValueError):
await connector.fetch_image_async(broken_img)

with pytest.raises(ValueError):
connector.fetch_image(broken_img)


@pytest.mark.asyncio
@pytest.mark.parametrize("video_url", TEST_VIDEO_URLS)
@pytest.mark.parametrize("num_frames", [-1, 32, 1800])
Expand Down
30 changes: 19 additions & 11 deletions vllm/multimodal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import numpy as np
import numpy.typing as npt
import torch
from PIL import Image
from PIL import Image, UnidentifiedImageError

import vllm.envs as envs
from vllm.connections import HTTPConnection, global_http_connection
Expand Down Expand Up @@ -185,11 +185,15 @@ def fetch_image(
"""
image_io = ImageMediaIO(image_mode=image_mode)

return self.load_from_url(
image_url,
image_io,
fetch_timeout=envs.VLLM_IMAGE_FETCH_TIMEOUT,
)
try:
return self.load_from_url(
image_url,
image_io,
fetch_timeout=envs.VLLM_IMAGE_FETCH_TIMEOUT,
)
except UnidentifiedImageError as e:
# convert to ValueError to be properly caught upstream
raise ValueError(str(e)) from e
Comment on lines +194 to +196
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This try...except block is a good way to handle the UnidentifiedImageError and convert it to a ValueError. This ensures that the error is caught and handled upstream.

Consider adding a more specific error message to the ValueError to provide more context to the user. For example, include the original URL that caused the error.

Suggested change
except UnidentifiedImageError as e:
# convert to ValueError to be properly caught upstream
raise ValueError(str(e)) from e
except UnidentifiedImageError as e:
# convert to ValueError to be properly caught upstream
raise ValueError(f"Failed to load image from URL {image_url}: {str(e)}") from e


async def fetch_image_async(
self,
Expand All @@ -204,11 +208,15 @@ async def fetch_image_async(
"""
image_io = ImageMediaIO(image_mode=image_mode)

return await self.load_from_url_async(
image_url,
image_io,
fetch_timeout=envs.VLLM_IMAGE_FETCH_TIMEOUT,
)
try:
return await self.load_from_url_async(
image_url,
image_io,
fetch_timeout=envs.VLLM_IMAGE_FETCH_TIMEOUT,
)
except UnidentifiedImageError as e:
# convert to ValueError to be properly caught upstream
raise ValueError(str(e)) from e
Comment on lines +217 to +219
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the fetch_image function, this try...except block handles the UnidentifiedImageError in the asynchronous version. Consider adding a more specific error message to the ValueError to provide more context to the user. For example, include the original URL that caused the error.

Suggested change
except UnidentifiedImageError as e:
# convert to ValueError to be properly caught upstream
raise ValueError(str(e)) from e
except UnidentifiedImageError as e:
# convert to ValueError to be properly caught upstream
raise ValueError(f"Failed to load image from URL {image_url}: {str(e)}") from e


def fetch_video(
self,
Expand Down