Skip to content
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: 9 additions & 4 deletions litellm/llms/fireworks_ai/chat/transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,16 @@ def _add_transform_inline_image_block(
): # allow user to toggle this feature.
return content
if isinstance(content["image_url"], str):
content["image_url"] = f"{content['image_url']}#transform=inline"
# Skip base64 data URLs — appending #transform=inline corrupts the
# base64 payload and causes an "Incorrect padding" decode error on
# the Fireworks side. Data URLs are already inlined by definition.
# Lower-case before checking: URI schemes are case-insensitive (RFC 3986).
if not content["image_url"].lower().startswith("data:"):
content["image_url"] = f"{content['image_url']}#transform=inline"
elif isinstance(content["image_url"], dict):
content["image_url"][
"url"
] = f"{content['image_url']['url']}#transform=inline"
url = content["image_url"]["url"]
if not url.lower().startswith("data:"):
content["image_url"]["url"] = f"{url}#transform=inline"
Comment on lines 187 to +197
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing test cases for the data: URL fix

The fix adds guards for both the str and dict branches, but no test cases were added to validate this behaviour. The existing test_transform_inline parametrized test in tests/llm_translation/test_fireworks_ai_translation.py covers HTTP URLs and vision-model bypass, but has no coverage for data: URLs (the exact scenario described in the linked issue).

The pre-submission checklist also explicitly requires at least one test in tests/test_litellm/. Without it, a future refactor could reintroduce the regression silently. The following cases are missing:

  • str branch: {"image_url": "data:image/png;base64,abc123"} → URL should remain unchanged
  • dict branch: {"image_url": {"url": "data:image/jpeg;base64,xyz=="}} → URL should remain unchanged

Example additions to the test_transform_inline parametrize list:

(
    {"image_url": "data:image/png;base64,iVBORw0KGgo="},
    "gpt-4",
    "data:image/png;base64,iVBORw0KGgo=",  # must not be modified
),
(
    {"image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ=="}},
    "gpt-4",
    {"url": "data:image/jpeg;base64,/9j/4AAQ=="},  # must not be modified
),

Rule Used: What: Ensure that any PR claiming to fix an issue ... (source)

return content

def _transform_tools(
Expand Down
18 changes: 18 additions & 0 deletions tests/llm_translation/test_fireworks_ai_translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,24 @@ def test_document_inlining_example(disable_add_transform_inline_image_block):
"vision-gpt",
"http://example.com/image.png",
),
# data: URLs must never have #transform=inline appended — doing so
# corrupts the base64 payload (fixes #23583).
# URI schemes are case-insensitive (RFC 3986) so check all variants.
(
{"image_url": "data:image/png;base64,iVBORw0KGgo="},
"gpt-4",
"data:image/png;base64,iVBORw0KGgo=",
),
(
{"image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ=="}},
"gpt-4",
{"url": "data:image/jpeg;base64,/9j/4AAQ=="},
),
(
{"image_url": "Data:image/png;base64,iVBORw0KGgo="},
"gpt-4",
"Data:image/png;base64,iVBORw0KGgo=",
),
],
)
def test_transform_inline(content, model, expected_url):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,35 @@ def test_get_supported_openai_params_reasoning_effort():
assert "reasoning_effort" not in unsupported_params


def test_add_transform_inline_image_block_skips_data_urls():
"""
data: URLs must not have #transform=inline appended — doing so corrupts the
base64 payload and raises binascii.Error: Incorrect padding on the Fireworks side.
Regression test for https://github.com/BerriAI/litellm/issues/23583
"""
config = FireworksAIConfig()
data_url = "data:image/jpeg;base64,/9j/4AAQSkZJRgAB"

# str branch
str_content = {"type": "image_url", "image_url": data_url}
result = config._add_transform_inline_image_block(
str_content, model="non-vision-model", disable_add_transform_inline_image_block=False
)
assert result["image_url"] == data_url, "data URL must not be modified (str branch)"

# dict branch
dict_content = {"type": "image_url", "image_url": {"url": data_url}}
result = config._add_transform_inline_image_block(
dict_content, model="non-vision-model", disable_add_transform_inline_image_block=False
)
assert result["image_url"]["url"] == data_url, "data URL must not be modified (dict branch)"

# regular https URL should still get the suffix
https_content = {"type": "image_url", "image_url": "https://example.com/image.jpg"}
result = config._add_transform_inline_image_block(
https_content, model="non-vision-model", disable_add_transform_inline_image_block=False
)
assert result["image_url"].endswith("#transform=inline"), "https URL should get #transform=inline"
@pytest.mark.parametrize(
Comment on lines +141 to 142
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing blank lines between test functions

PEP 8 requires two blank lines between top-level definitions. There is no blank line between the closing assert of test_add_transform_inline_image_block_skips_data_urls and the @pytest.mark.parametrize decorator that begins the next test. While this does not affect test execution, it makes the file harder to read and will typically trigger linting warnings.

Suggested change
assert result["image_url"].endswith("#transform=inline"), "https URL should get #transform=inline"
@pytest.mark.parametrize(
assert result["image_url"].endswith("#transform=inline"), "https URL should get #transform=inline"
@pytest.mark.parametrize(

"api_base, expected_url_prefix",
[
Expand Down
Loading