fix(embeddings): accept encoding_format="float" for vertex_ai/gemini embeddings - #33617
Conversation
…embeddings OpenAI SDKs (and litellm's own client since ~1.84) send encoding_format='float' by default, but the vertex embedding config only supports ['dimensions'], so get_optional_params_embeddings raised UnsupportedParamsError at the provider default value. Any OpenAI-compatible client talking to a litellm proxy with vertex embedding models got a 400 unless the operator set proxy-wide drop_params: true. Float lists are exactly what the vertex API returns, so the param is a no-op: pop it before validation. Other values (e.g. 'base64') keep the existing unsupported-param behavior (dropped with drop_params, raise otherwise). Fixes #33173 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Greptile SummaryThis PR fixes a usability regression where
Confidence Score: 4/5Safe to merge; the change is a small, well-tested no-op strip of a default parameter that previously caused a spurious error. The functional fix is correct and the tests are thorough. The one concern is placement: the stripping logic lives in utils.py rather than in VertexAITextEmbeddingConfig where provider-specific transform logic belongs. If vertex_ai or gemini ever gain a BaseEmbeddingConfig registration in get_provider_embedding_config, the early-return path would bypass these lines entirely and the bug would silently reappear. The fix works today but is fragile by design. litellm/utils.py — the new strip logic sits inside the legacy
|
| Filename | Overview |
|---|---|
| litellm/utils.py | Adds 6 lines in the existing vertex_ai/gemini embedding branch to pop encoding_format="float" from non_default_params before the unsupported-param check; logic is correct but placed in utils.py rather than the provider config class where it belongs |
| tests/test_litellm/test_utils.py | Adds five focused unit tests covering float accepted/dropped for both vertex_ai and gemini providers, base64 rejected without drop_params, base64 dropped with drop_params, and dimensions still mapped — all mocked, no network calls |
Reviews (1): Last reviewed commit: "fix(embeddings): accept encoding_format=..." | Re-trigger Greptile
| elif custom_llm_provider == "vertex_ai" or custom_llm_provider == "gemini": | ||
| # OpenAI SDKs (and litellm's own client) send encoding_format="float" | ||
| # by default; float lists are exactly what the vertex API returns, so | ||
| # the param is a no-op — don't reject the provider default. Other | ||
| # values (e.g. "base64") stay on the unsupported-param path below. | ||
| if non_default_params.get("encoding_format") == "float": | ||
| non_default_params.pop("encoding_format") |
There was a problem hiding this comment.
Provider-specific logic placed outside
llms/ directory
The encoding-format stripping is added directly to utils.py rather than to the provider's own config class. VertexAITextEmbeddingConfig (in litellm/llms/vertex_ai/vertex_embeddings/transformation.py) already owns both get_supported_openai_params() and map_openai_params() — the correct fix is to add "encoding_format" to the supported-params list and silently drop it (when "float") inside map_openai_params(). Placing the strip logic in utils.py means the behaviour won't automatically apply when the provider eventually gets a BaseEmbeddingConfig registration in get_provider_embedding_config (the early-return path would then bypass these lines entirely).
Rule Used: What: Avoid writing provider-specific code outside... (source)
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Tested live against a local proxy on
Full walkthrough and test report: https://app.devin.ai/sessions/2a3db9e7f3234370988a77b458d0a202 |
69a476f
into
litellm_oss_daily_2026_07_16
* fix(embeddings): accept encoding_format='float' for vertex_ai/gemini embeddings (#33617) OpenAI SDKs (and litellm's own client since ~1.84) send encoding_format='float' by default, but the vertex embedding config only supports ['dimensions'], so get_optional_params_embeddings raised UnsupportedParamsError at the provider default value. Any OpenAI-compatible client talking to a litellm proxy with vertex embedding models got a 400 unless the operator set proxy-wide drop_params: true. Float lists are exactly what the vertex API returns, so the param is a no-op: pop it before validation. Other values (e.g. 'base64') keep the existing unsupported-param behavior (dropped with drop_params, raise otherwise). Fixes #33173 Co-authored-by: Mihidum Hettiyahandi <55163074+mihidumh@users.noreply.github.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * feat(guardrails): add Singulr guardrail integration for LiteLLM gateway (#31302) * singulr guardrail support for litellm gateway * Update litellm/proxy/guardrails/guardrail_hooks/singulr/singulr.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix comments * improvement * fix: resolve review comments and implement requested improvements * fix:Guardrail bypass through uninspected messages * fix:tool text scanning * fix: Legacy function definitions bypass scanning by adding indirect message scaning * chore: remove unintended basedpyright budget file * fix:Response schema bypasses guardrail scanning (response_format.json_schema) * chore: restore basedpyright-code-budget.json and update lint baselines Restores the file deleted in c698b88 to match upstream litellm_internal_staging. Regenerates basedpyright and ruff-strict budget baselines via make lint-budget-update. * fix: scan system messages as indirect prompt injection in Singulr guardrail * chore: restore lint budget files to upstream baseline * fix: resolve ruff UP006 and I001 violations in singulr guardrail * Update litellm/proxy/guardrails/guardrail_hooks/singulr/singulr.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * resolve review comments on Singulr guardrail * fix: scan tool call results as indirect prompt injection in Singulr guardrail * Apply suggestion from @greptile-apps[bot] Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * minor * formating fix * refactor: shift extraction logic to singulr side * refactor:keep precall hook only * fix:formatting * fix:linting * improve config description * Trigger CI * fix * fix:field description * fix:errors due to change in field names * style: apply ruff line-wrap formatting to singulr guardrail * fix:exception * fix:formatting * fix playground * improved * Update litellm/proxy/guardrails/guardrail_hooks/singulr/singulr.py Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com> * Update litellm/proxy/guardrails/guardrail_hooks/singulr/singulr.py Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com> * fix * fix ci issues * remove uv.lock from pr * fix * fix:resolved comments * chore: trigger CI * remove uv.lock * fix * fix linting * fix linting * fix linting * remove doc strings * remove test fixes * chore: retrigger CI * change in singulr api contract * remove some ut * send litellm call_id to singulr --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: aniket-kardile <aniket.kardile@singulr.ai> Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com> * Fix non-conformant UUIDv7 generation in native Opik integration (#31294) create_uuid7() encoded the timestamp in units of 16 seconds instead of milliseconds, so the top 48 bits came out ~4096x the real unix-ms. Opik's backend validates the embedded UUIDv7 timestamp on ingestion (OPIK-7067); the bad encoding decoded to ~year 2201 and every trace/span batch was rejected with HTTP 400. Rewrite create_uuid7() to be RFC 9562 conformant (top 48 bits = unix-ms), using the standard library only so no new dependency is added. Add unit tests covering UUIDv7 validity and millisecond timestamp encoding. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(proxy): expose uvicorn concurrency limit (#33077) Expose uvicorn's limit_concurrency as a --limit_concurrency CLI flag and LIMIT_CONCURRENCY environment variable. Uvicorn counts both active tasks and accepted connections and returns HTTP 503 once the configured limit is reached. Reject non-positive limits at CLI parse time and only add the setting to the uvicorn startup arguments. Because idle connections also consume capacity, deployments should use upstream connection/header timeouts and per-client connection limits. * test: reorder test_utils tail to keep the daily merge conflict-free (#33788) The daily OSS branch and litellm_internal_staging each appended an independent test block at the very end of tests/test_litellm/test_utils.py, so merging the two collides on that shared end-of-file position even though the additions are unrelated (this branch adds the vertex embedding encoding-format tests; staging adds the per-model prompt-cache-minimum tests). Moving this branch's new TestVertexEmbeddingEncodingFormat class above test_gemini_image_models_do_not_support_reasoning, which both branches share, gives the two additions different anchors, so git applies both without a conflict and without pulling staging into this branch. Pure reorder; no test bodies change --------- Co-authored-by: Mateo Wang <277851410+mateo-berri@users.noreply.github.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Mihidum Hettiyahandi <55163074+mihidumh@users.noreply.github.com> Co-authored-by: madan-singulr <150280287+madan-singulr@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: aniket-kardile <aniket.kardile@singulr.ai> Co-authored-by: veria-ai[bot] <224490171+veria-ai[bot]@users.noreply.github.com> Co-authored-by: Aliaksandr Kuzmik <98702584+alexkuzmik@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Salva Madrid <50212436+salvamadrid@users.noreply.github.com>

Relevant issues
Fixes #33173
Internal replacement branch for OSS PR #33293 by Mihidum Hettiyahandi (@mihidumh); original authorship is preserved on the commits
Linear ticket
Pre-Submission checklist
Screenshots / Proof of Fix
Captured live against a proxy on
localhost:4000at commit6d73fcfbdc, using a real Gemini embedding modelConfig:
encoding_format="float"(OpenAI SDK default) is now accepted and returns a real float vector:Other formats keep the existing unsupported-param behavior;
base64withoutdrop_paramsstill errors:Before the fix, the
floatrequest also failed with the same UnsupportedParamsError even though float is exactly what the Vertex/Gemini embeddings API returnsType
🐛 Bug Fix
Changes
For
vertex_ai/geminiembeddings,encoding_format="float"is popped from the params before the unsupported-param check, since it is the OpenAI SDK default and a no-op for these providers (they return float lists natively). Any other value (e.g.base64) stays on the existing unsupported-param path, so it still raises unlessdrop_paramsis setFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/2a3db9e7f3234370988a77b458d0a202