fix: handle explicit outputInfo: null in Vertex AI batch response - #34473
Conversation
Vertex AI can return HTTP 200 for a create_batch/get_batch call with an
explicit "outputInfo": null body (the output directory is assigned
asynchronously and may not be populated yet at response time).
_get_output_file_id_from_vertex_ai_batch_response did:
response.get("outputInfo", OutputInfo()).get("gcsOutputDirectory", "")
dict.get(key, default) only substitutes default when the key is absent,
not when it is present but explicitly None, so this crashed with:
AttributeError: 'NoneType' object has no attribute 'get'
surfaced to callers as an opaque openai.InternalServerError 500 from
litellm.create_batch()/retrieve_batch() for any Vertex AI batch job,
regardless of whether the job ultimately succeeds.
Fixed by guarding with `response.get("outputInfo") or OutputInfo()`,
matching the existing null-safe pattern already used by the sibling
_get_input_file_id_from_vertex_ai_batch_response for inputConfig. The
existing outputConfig fallback branch (a few lines below) already
handles this case correctly once it's reachable - it just never was.
Added 2 regression tests covering outputInfo: null with and without an
outputConfig fallback available.
Greptile SummaryThis PR safely handles an explicit null
Confidence Score: 5/5The PR appears safe to merge No blocking failures remain
|
| Filename | Overview |
|---|---|
| litellm/llms/vertex_ai/batches/transformation.py | Normalizes explicit null outputInfo to an empty typed mapping before accessing gcsOutputDirectory |
| tests/test_litellm/llms/vertex_ai/batches/test_transformation.py | Adds focused regression tests for null outputInfo, including fallback and absent-output cases |
Reviews (3): Last reviewed commit: "test: drop explanatory comment from regr..." | Re-trigger Greptile
|
bugbot run |
Greptile SummaryHandles nullable Vertex AI batch output metadata
Confidence Score: 5/5The PR appears safe to merge because the nullable response case is handled without altering valid populated-response behavior The changed helper converts absent or null output metadata into the same empty mapping already used for missing data, allowing the established outputConfig fallback to run, and focused tests cover both fallback outcomes
|
| Filename | Overview |
|---|---|
| litellm/llms/vertex_ai/batches/transformation.py | Safely normalizes null output metadata before accessing its fields while preserving existing fallback behavior |
| tests/test_litellm/llms/vertex_ai/batches/test_transformation.py | Adds focused regression tests covering explicit null output metadata with and without outputConfig |
Reviews (2): Last reviewed commit: "fix: handle explicit outputInfo: null in..." | Re-trigger Greptile
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 4cfb0f8. Configure here.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c5d9dfd. Configure here.
…rriAI#34473) * fix: handle explicit outputInfo: null in Vertex AI batch response Vertex AI can return HTTP 200 for a create_batch/get_batch call with an explicit "outputInfo": null body (the output directory is assigned asynchronously and may not be populated yet at response time). _get_output_file_id_from_vertex_ai_batch_response did: response.get("outputInfo", OutputInfo()).get("gcsOutputDirectory", "") dict.get(key, default) only substitutes default when the key is absent, not when it is present but explicitly None, so this crashed with: AttributeError: 'NoneType' object has no attribute 'get' surfaced to callers as an opaque openai.InternalServerError 500 from litellm.create_batch()/retrieve_batch() for any Vertex AI batch job, regardless of whether the job ultimately succeeds. Fixed by guarding with `response.get("outputInfo") or OutputInfo()`, matching the existing null-safe pattern already used by the sibling _get_input_file_id_from_vertex_ai_batch_response for inputConfig. The existing outputConfig fallback branch (a few lines below) already handles this case correctly once it's reachable - it just never was. Added 2 regression tests covering outputInfo: null with and without an outputConfig fallback available. * test: drop explanatory comment from regression test --------- Co-authored-by: htourinho-clgx <htourinho@cotality.com>
TLDR
Problem this solves:
outputInfo: nullcrash litellmopenai.InternalServerError500 fromcreate_batch()/retrieve_batch()How it solves it:
outputInfowithor OutputInfo()before calling.get()on itinputConfigin the sibling helperRelevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Vertex AI assigns the batch output directory asynchronously, so its API can return HTTP 200 with an explicit
"outputInfo": nullbody.dict.get(key, default)only substitutes the default when the key is absent, not when it is present but explicitlyNone, so the old code crashed on exactly that response shapeBefore, at the parent of the fix commit (
bd753aecf3, pre-fix code):After, at the fix commit (
4cfb0f8d89), same input:No crash; the response falls through cleanly to the existing
outputConfig-derived path a few lines below, which already handles this case correctly once it is reachableThe original PR verified the unguarded call is present in litellm 1.83.10 through 1.93.0 by direct source inspection of each published version. There is no live production reproduction attached; the response shape used above is the one Vertex AI's own API is documented to allow. The 2 new regression tests in
tests/test_litellm/llms/vertex_ai/batches/test_transformation.pycoveroutputInfo: nullwith and without anoutputConfigfallback, and the full file (44 tests) passes locally at4cfb0f8d89Type
🐛 Bug Fix
Changes
litellm/llms/vertex_ai/batches/transformation.pyguardsoutputInfobeing explicitlyNonebefore calling.get()on it, matching the null-safe pattern already used by the sibling_get_input_file_id_from_vertex_ai_batch_response.tests/test_litellm/llms/vertex_ai/batches/test_transformation.pyadds 2 regression tests foroutputInfo: null, with and without anoutputConfigfallback availableBehavior changes
retrieve_batch()/create_batch()against Vertex AI no longer raise a 500 when the response containsoutputInfo: null; they now fall through to theoutputConfigfallback (or return the batch without an output file id if that is also absent). No other behavior changesCredit
Adopted from #34097 by @htourinho-clgx, mirrored onto a
litellm_branch so CircleCI and the internal lint workflow run. The original fix commit is cherry-picked as-is with the author's commit metadata preserved. The original PR's follow-up commit bumpingui/litellm-dashboarddependencies (brace-expansion, js-yaml) is intentionally excluded; this PR carries onlytransformation.pyand its test fileFinal Attestation
Note
Low Risk
Narrow null-guard in batch response parsing with regression tests; no auth, data, or API contract changes beyond avoiding the crash.
Overview
Fixes a crash when Vertex AI batch APIs return
"outputInfo": null(common while output paths are assigned asynchronously).dict.get("outputInfo", OutputInfo())does not replace an explicitNone, so the old code called.get()onNoneandcreate_batch()/retrieve_batch()surfaced as 500s._get_output_file_id_from_vertex_ai_batch_responsenow usesresponse.get("outputInfo") or OutputInfo()before readinggcsOutputDirectory, so the handler can fall through tooutputConfiglike it already did for missing or emptyoutputInfo. Two regression tests coveroutputInfo: nullwith and without that fallback.Reviewed by Cursor Bugbot for commit c5d9dfd. Bugbot is set up for automated code reviews on this repo. Configure here.