mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(batch): avoid reading a nonexistent output artifact for completed batches
Completed batches that contain only failed requests do not generate an output file, leaving output_file_id unset while the failures are recorded through error_file_id instead. The completion handler attempted to read the output payload regardless of whether an output file actually existed. During retrieve polling this caused the logging pipeline to fail with "Output file id is None cannot retrieve file content", preventing normal completion bookkeeping from running. Skip output retrieval when no output file is available and return an empty batch summary (zero usage, zero cost, no model entries). The lower-level file retrieval helper still reports an error if it is called directly with an invalid or missing file identifier. Closes #33987
This commit is contained in:
parent
add095b494
commit
f91e698adb
2 changed files with 32 additions and 0 deletions
|
|
@ -58,6 +58,17 @@ async def _handle_completed_batch(
|
|||
model_name: Optional model name
|
||||
litellm_params: Optional litellm parameters containing credentials (api_key, api_base, etc.)
|
||||
"""
|
||||
# A completed batch whose request lines all failed has no output file - the
|
||||
# results are written to a separate error_file_id and output_file_id is None.
|
||||
# There is nothing to price or measure, so report an empty result set instead
|
||||
# of calling _fetch_batch_output_file_content, which raises on a missing
|
||||
# output file. Without this guard the logging worker crashes on every
|
||||
# aretrieve_batch poll and the completed batch's zero-cost accounting is lost.
|
||||
# The generic retrieval helper keeps raising for callers that explicitly ask
|
||||
# for a missing output file.
|
||||
if batch.output_file_id is None:
|
||||
return 0.0, Usage(prompt_tokens=0, completion_tokens=0, total_tokens=0), []
|
||||
|
||||
file_content = await _fetch_batch_output_file_content(batch, custom_llm_provider, litellm_params=litellm_params)
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -976,6 +976,27 @@ async def test_handle_completed_batch_orchestration(monkeypatch):
|
|||
assert models == ["gpt-4o"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_completed_batch_no_output_file_is_zero(monkeypatch):
|
||||
"""
|
||||
Regression: an all-error batch completes with output_file_id=None (results go
|
||||
to a separate error_file_id). _handle_completed_batch must report an empty
|
||||
result set - zero cost, zero usage, no models - instead of letting the file
|
||||
fetch raise "Output file id is None" on every aretrieve_batch logging poll.
|
||||
"""
|
||||
# The output-file fetch must not even be attempted when there is no output file.
|
||||
async def _must_not_fetch(*args, **kwargs):
|
||||
pytest.fail("_fetch_batch_output_file_content should not be called")
|
||||
|
||||
monkeypatch.setattr(bu, "_fetch_batch_output_file_content", _must_not_fetch)
|
||||
|
||||
cost, usage, models = await bu._handle_completed_batch(_batch(None), custom_llm_provider="openai")
|
||||
|
||||
assert cost == 0.0
|
||||
assert (usage.prompt_tokens, usage.completion_tokens, usage.total_tokens) == (0, 0, 0)
|
||||
assert models == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_completed_batch_vertex_disable_transform_path(monkeypatch):
|
||||
raw_rows = [{"response": {"usageMetadata": {"promptTokenCount": 1, "candidatesTokenCount": 2}}}]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue