Skip to content

fix: handle explicit outputInfo: null in Vertex AI batch response - #34473

Merged
yucheng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_vertex_batch_outputinfo_null
Jul 24, 2026
Merged

fix: handle explicit outputInfo: null in Vertex AI batch response#34473
yucheng-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_vertex_batch_outputinfo_null

Conversation

@yucheng-berri

@yucheng-berri yucheng-berri commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Vertex AI batch responses with explicit outputInfo: null crash litellm
  • Callers see an opaque openai.InternalServerError 500 from create_batch() / retrieve_batch()

How it solves it:

  • Guard outputInfo with or OutputInfo() before calling .get() on it
  • Matches the null-safe pattern already used for inputConfig in the sibling helper

Relevant issues

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to 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": null body. dict.get(key, default) only substitutes the default when the key is absent, not when it is present but explicitly None, so the old code crashed on exactly that response shape

Before, at the parent of the fix commit (bd753aecf3, pre-fix code):

>>> raw_response = {"outputInfo": None, "outputConfig": {"gcsDestination": {"outputUriPrefix": "gs://bucket/output/"}}}
>>> raw_response.get("outputInfo", OutputInfo()).get("gcsOutputDirectory", "")
AttributeError: 'NoneType' object has no attribute 'get'

After, at the fix commit (4cfb0f8d89), same input:

>>> VertexAIBatchTransformation._get_output_file_id_from_vertex_ai_batch_response(raw_response)
'gs://bucket/output/predictions.jsonl'

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 reachable

The 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.py cover outputInfo: null with and without an outputConfig fallback, and the full file (44 tests) passes locally at 4cfb0f8d89

Type

🐛 Bug Fix

Changes

litellm/llms/vertex_ai/batches/transformation.py guards outputInfo being explicitly None before 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.py adds 2 regression tests for outputInfo: null, with and without an outputConfig fallback available

Behavior changes

retrieve_batch() / create_batch() against Vertex AI no longer raise a 500 when the response contains outputInfo: null; they now fall through to the outputConfig fallback (or return the batch without an output file id if that is also absent). No other behavior changes

Credit

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 bumping ui/litellm-dashboard dependencies (brace-expansion, js-yaml) is intentionally excluded; this PR carries only transformation.py and its test file

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Open in Devin Review

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 explicit None, so the old code called .get() on None and create_batch() / retrieve_batch() surfaced as 500s.

_get_output_file_id_from_vertex_ai_batch_response now uses response.get("outputInfo") or OutputInfo() before reading gcsOutputDirectory, so the handler can fall through to outputConfig like it already did for missing or empty outputInfo. Two regression tests cover outputInfo: null with and without that fallback.

Reviewed by Cursor Bugbot for commit c5d9dfd. Bugbot is set up for automated code reviews on this repo. Configure here.

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.
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@devin-ai-integration devin-ai-integration Bot left a comment

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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR safely handles an explicit null outputInfo in Vertex AI batch responses

  • Normalizes null outputInfo before reading the output directory
  • Preserves the existing outputConfig fallback and empty-result behavior
  • Adds regression coverage with and without an outputConfig fallback

Confidence Score: 5/5

The PR appears safe to merge

No blocking failures remain

Important Files Changed

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

Comment thread tests/test_litellm/llms/vertex_ai/batches/test_transformation.py Outdated
Comment thread litellm/llms/vertex_ai/batches/transformation.py
@yucheng-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Handles nullable Vertex AI batch output metadata

  • Falls back to an empty OutputInfo when outputInfo is explicitly null
  • Preserves the existing outputConfig fallback for deriving the output file path
  • Adds regression coverage for null metadata with and without a configured output location

Confidence Score: 5/5

The 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

Important Files Changed

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

@cursor cursor Bot left a comment

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.

✅ 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.

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_vertex_batch_outputinfo_null (c5d9dfd) with litellm_internal_staging (64aad58)1

Open in CodSpeed

Footnotes

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

@yucheng-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

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.

✅ 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.

@yucheng-berri
yucheng-berri merged commit 61d32c9 into litellm_internal_staging Jul 24, 2026
82 checks passed
@yucheng-berri
yucheng-berri deleted the litellm_vertex_batch_outputinfo_null branch July 24, 2026 22:10
Ericcwang23 pushed a commit to Ericcwang23/litellm that referenced this pull request Jul 27, 2026
…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>
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.

3 participants