Skip to content

fix(images): forward image_config on OpenRouter image edits - #30881

Open
Ewertonslv wants to merge 10 commits into
BerriAI:mainfrom
Ewertonslv:fix_openrouter_image_edit_image_config
Open

Ewertonslv wants to merge 10 commits into
BerriAI:mainfrom
Ewertonslv:fix_openrouter_image_edit_image_config

Conversation

@Ewertonslv

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes #30753

Type

🐛 Bug Fix

Changes

image_config was honored on OpenRouter image generation but silently dropped on image edits. The default edit branch in image_edit() never merged non_default_params (which still carries image_config after the optional-param whitelist filters it out) before calling the handler, unlike the bedrock, stability, and black_forest_labs branches. This merges non_default_params for the openrouter path so image_config survives; OpenRouter's transform already forwards extra top-level params into the chat-completions body, so it then reaches the provider.

Added a regression test asserting image_config is forwarded to the handler for OpenRouter image edits

Proof of fix

The regression test fails on current code (image_config is absent from the forwarded params) and passes with the fix. Live proxy verification against an OpenRouter image-edit model to follow

Pre-Submission checklist

  • I have added meaningful tests
  • My PR's scope is as isolated as possible; it only solves 1 specific problem

image_config was honored on OpenRouter image generation but silently dropped on image edits.
The default edit branch in image_edit() never merged non_default_params (which still carries
image_config after the optional-param whitelist filters it out) before calling the handler,
unlike the bedrock, stability, and black_forest_labs branches. Merge non_default_params for the
openrouter path so image_config survives; OpenRouter's transform already forwards extra
top-level params into the chat-completions body, so it then reaches the provider

Fixes BerriAI#30753
@greptile-apps

greptile-apps Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug where non-default params (notably image_config) were silently dropped on the default image_edit handler path, unlike the bedrock, stability, and black_forest_labs branches which already called image_edit_request_params.update(non_default_params). The fix makes that merge unconditional for all fallthrough providers. It also adds a hardening layer in the OpenRouter transform to block routing-control fields from being forwarded into the upstream /chat/completions body.

  • litellm/images/main.py: Adds image_edit_request_params.update(non_default_params) unconditionally before the default base_llm_http_handler.image_edit_handler call, so params like image_config now reach every fallthrough provider (openrouter, openai, azure, vertex_ai, …) instead of being silently dropped.
  • litellm/llms/openrouter/image_edit/transformation.py: Introduces OPENROUTER_ROUTING_CONTROL_PARAMS and filters those keys inside transform_image_edit_request, ensuring that image_config passes through while routing-control fields do not enter the upstream chat body.
  • Tests: Four new mock-only tests verify image_config forwarding for both openrouter and generic providers, and confirm that routing-control params are stripped while image_config survives — all without real network calls.

Confidence Score: 5/5

Safe to merge — the change is a minimal, targeted extension of an existing pattern already applied on three other provider branches, and the new hardening layer in the OpenRouter transform is well-covered by the added mock tests.

The unconditional non_default_params merge exactly mirrors the bedrock/stability/black_forest_labs branches and introduces no new code paths for providers that previously worked correctly. The routing-control filter in transform_image_edit_request is additive, uses a frozenset for O(1) lookup, and is validated by a dedicated mock test that checks both the blocked keys and the expected passthrough of image_config. All four new tests are mock-only, consistent with the repo's test isolation rules.

No files require special attention.

Important Files Changed

Filename Overview
litellm/images/main.py Adds unconditional image_edit_request_params.update(non_default_params) before the default handler call, mirroring the pattern already present on the bedrock/stability/black_forest_labs branches and fixing the silent param drop for all fallthrough providers.
litellm/llms/openrouter/image_edit/transformation.py Adds OPENROUTER_ROUTING_CONTROL_PARAMS frozenset and filters those keys out of the forwarded params in transform_image_edit_request, preventing routing-control fields from being injected into the upstream chat body while allowing legitimate params like image_config through.
tests/test_litellm/images/test_image_edit_utils.py Adds TestImageEditDefaultPathForwardsNonDefaultParams with two mock-only regression tests covering both openrouter and openai (generic fallthrough) paths; no real network calls.
tests/test_litellm/llms/openrouter/image_edit/test_openrouter_image_edit_transformation.py Adds test_transform_image_edit_request_drops_openrouter_routing_controls verifying that routing-control keys are blocked while image_config still passes through; mock-only, no real network calls.

Reviews (3): Last reviewed commit: "fix(openrouter): drop routing-control fi..." | Re-trigger Greptile

Comment thread litellm/images/main.py Outdated
@codecov

codecov Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...tellm/llms/openrouter/image_edit/transformation.py 83.33% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Muhtasim-Munif-Fahim Muhtasim-Munif-Fahim left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Small focused fix. \image_config\ was being dropped for OpenRouter image edits because the default branch never merged
on_default_params. The 2-line fix is correct and the regression test validates it. LGTM.

@Ewertonslv

Copy link
Copy Markdown
Contributor Author

@greptileai

@Sameerlite

Copy link
Copy Markdown
Contributor

Thanks for the contribution! A couple of things to get this ready:

  • Greptile threads — There are unresolved review threads from Greptile. Could you address or reply to those?
  • Proof of working — Could you add some evidence the change works? Screenshots, test output, a curl request/response, or before/after logs really help speed up the review.

Once that's in, we'll take another look — appreciate the work on this! 🙏

…all providers

Greptile review thread: the merge was gated on custom_llm_provider == openrouter,
but every fallthrough provider (openai, azure, vertex_ai, ...) hits the same
base_llm_http_handler.image_edit_handler call and silently dropped extra params like
image_config. Make the merge unconditional before the default handler call, mirroring
the bedrock/stability/black_forest_labs branches. Generalize the regression test to
also cover a non-openrouter provider.
@Ewertonslv

Copy link
Copy Markdown
Contributor Author

@Sameerlite thanks for the review! Both asks are addressed:

1. Greptile thread — resolved (and adopted). The reviewer was right that gating the merge on openrouter left every other fallthrough provider (openai, azure, vertex_ai, …) with the same silent-drop bug. I moved the non_default_params merge above the provider guard so it now runs unconditionally on the default handler path, mirroring the bedrock/stability/black_forest_labs branches. The regression test was generalized to also cover a non-openrouter provider.

2. Proof of working. Before/after on the regression tests (the new openai case fails on the old openrouter-only guard, both pass with the unconditional merge):

# BEFORE (merge gated on openrouter only)
$ pytest tests/test_litellm/images/test_image_edit_utils.py::TestImageEditDefaultPathForwardsNonDefaultParams -q
FAILED ...::test_default_path_forwards_image_config_for_non_openrouter_provider
1 failed, 1 passed

# AFTER (merge unconditional on the default handler path)
$ pytest tests/test_litellm/images/test_image_edit_utils.py::TestImageEditDefaultPathForwardsNonDefaultParams -q
2 passed

# Full file — no regressions
$ pytest tests/test_litellm/images/test_image_edit_utils.py -q
16 passed

The tests patch base_llm_http_handler and assert image_config survives into image_edit_optional_request_params for both openrouter and openai. Ready for another look 🙏

Comment thread litellm/images/main.py Outdated
@veria-ai

veria-ai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 1 · PR risk: 0/10

@Sameerlite

Copy link
Copy Markdown
Contributor

Great work addressing the Greptile feedback and broadening the fix to all default-path providers, @Ewertonslv — the before/after test output is exactly what we need. Triggering a fresh Greptile review against the updated head.\n\n@greptileai

The image-edit transform copied every forwarded optional param into the upstream
/chat/completions body. Since the default edit path now forwards non-default
params (so image_config survives), a caller could smuggle OpenRouter routing
controls (models/route/provider/transforms) into an allowed image-edit request
and redirect it to other models/providers, bypassing LiteLLM's model
authorization and budget checks. Skip those routing-control keys when building
the request body; image_config and other intended params still pass through.

Addresses the routing-control-bypass review finding on BerriAI#30881.
@Ewertonslv

Copy link
Copy Markdown
Contributor Author

Friendly ping, @Sameerlite — this one's been green since your last message (73/73 checks, all Greptile threads resolved, veria-ai reported no security concerns) and it's carrying an approval.

Is there anything else you'd like from me before it lands, or is it just waiting on a merge slot? Happy to rebase onto main if it's drifted. Thanks!

@Ewertonslv

Copy link
Copy Markdown
Contributor Author

@Sameerlite following up — I think this stalled on a mechanical issue rather than the review itself.

Your @greptileai re-trigger on Jun 25 fired at 03:49, but I pushed d95a25890 at 11:34 the same day, so Greptile's only review on this PR is still against the original commit f9fa37721. It never saw the two changes that actually matter:

  • b9dab763a — moved the non_default_params merge above the provider guard, so the default handler path forwards extra params for every fallthrough provider, not just openrouter (the Greptile P2 you asked me to address).
  • d95a25890 — response to veria-ai's Medium finding: transform_image_edit_request was copying every forwarded param into the /chat/completions body, so a proxy caller could smuggle models / route / provider / transforms into an image-edit request for an allowed model and get routed elsewhere, outside model-authorization and budget checks. Added OPENROUTER_ROUTING_CONTROL_PARAMS to drop those; image_config still passes through, and the regression test fails without the fix.

Re-triggering Greptile against the current head:

@greptileai

For reference, the bug is still live on the default branch: the final base_llm_http_handler.image_edit_handler(...) call in litellm/images/main.py has no image_edit_request_params.update(non_default_params), unlike the bedrock / stability / black_forest_labs branches right above it. 73/73 checks green, no conflicts.

@yuneng-berri
yuneng-berri deleted the branch BerriAI:main September 13, 2026 04:25
@yuneng-berri yuneng-berri reopened this Sep 13, 2026
@devin-ai-integration
devin-ai-integration Bot changed the base branch from litellm_internal_staging to main September 23, 2026 16:01
@devin-ai-integration
devin-ai-integration Bot requested a review from a team September 23, 2026 16:01
@codspeed

codspeed Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing Ewertonslv:fix_openrouter_image_edit_image_config (6654ee8) with main (b0e0a30)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (e843cb7) during the generation of this report, so b0e0a30 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

After merging main, the unconditional non_default_params merge on the
default image_edit path collided with two upstream changes:

- multipart OpenAI-compatible routes now merge caller params themselves
  (flattened, extra_body taking precedence); re-merging the raw params
  let seed=42 override extra_body={"seed": 7} and undid the flattening.
- provider configs such as Azure AI FLUX.2 map supported params
  (size -> width/height, guidance "4.5" -> 4.5); the raw merge re-added
  size and overwrote the coerced values.

Skip the fallback merge when the multipart branch already merged, and
otherwise forward only params the provider config does not map and that
are not already in the request (e.g. OpenRouter's image_config).
@Ewertonslv

Copy link
Copy Markdown
Contributor Author

Heads-up on a follow-up change since the approval. After the base moved to main, the unconditional non_default_params merge on the default edit path collided with two newer changes there, and CI caught both:

  • Multipart OpenAI-compatible routes now merge caller params themselves (flattened, with extra_body taking precedence), so re-merging the raw params broke test_image_edit_extra_body_takes_precedence_over_kwargs.
  • Provider configs such as Azure AI FLUX.2 map their supported params (size → width/height, guidance coerced to float), and the raw merge re-added size and overwrote the coerced values.

9a20dca6a4 skips the fallback merge when the multipart branch already merged, and otherwise forwards only params the provider config doesn't map and that aren't already in the request, so OpenRouter's image_config still reaches the upstream call. The regression tests now cover a non-multipart provider (vertex_ai) alongside openrouter.

The remaining interactions/test_openapi_compliance failures come from the live spec at ai.google.dev and are unrelated to this PR.

@Ewertonslv

Copy link
Copy Markdown
Contributor Author

Merged current main into the branch. No changes to the fix itself. The interactions/test_openapi_compliance failures are gone now that #43958 repaired those spec lookups: 102/103 checks pass.

The one red check is proxy-infra / Upload coverage to Codecov, which failed downloading the coverage artifact (Failed to GetSignedArtifactURL: ECONNRESET), not on a test. I can't re-run jobs from a fork. Could someone re-run that job when convenient? Thanks!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: image_config silently dropped on /v1/images/edits for OpenRouter image models (honored on /v1/images/generations)

4 participants