fix(batches): keep managed files on owner

Managed files and batches are provider-owned. Cross-model fallbacks can dispatch creation with credentials that cannot access the input file and replace the owning provider's validation error.\n\nCloses #35359
This commit is contained in:
Rithvik Mysore Suresh 2026-07-31 10:16:35 -04:00
parent 3c2264cfac
commit f0ffc6507e
3 changed files with 51 additions and 2 deletions

View file

@ -262,7 +262,10 @@ async def create_batch(
detail={"error": "LLM Router not initialized. Ensure models added to proxy."},
)
response = await llm_router.acreate_batch(**_create_batch_data)
response = await llm_router.acreate_batch(
**_create_batch_data,
disable_fallbacks=True,
)
response.input_file_id = input_file_id
response._hidden_params["unified_file_id"] = unified_file_id
else:

View file

@ -469,7 +469,7 @@ async def test_create__fallback_body_custom_llm_provider(harness):
@pytest.mark.asyncio
async def test_create__unified_file_id_single_model(harness):
async def test_create__unified_file_id_single_model_disables_cross_model_fallbacks(harness):
set_body(
harness,
{
@ -489,6 +489,7 @@ async def test_create__unified_file_id_single_model(harness):
harness.litellm_acreate.assert_not_called()
# model injected from the unified id, input_file_id restored, hidden param set
assert harness.router_kwargs()["model"] == "gpt-4o-mini"
assert harness.router_kwargs()["disable_fallbacks"] is True
assert resp.input_file_id == "litellm_proxy_unified_id"
assert resp._hidden_params["unified_file_id"] == "unified-xyz"

View file

@ -6054,6 +6054,51 @@ def test_get_configured_token_limits_coerces_numeric_strings():
assert router.get_configured_token_limits("quoted-limits-model") == (32000, 8000)
@pytest.mark.asyncio
async def test_acreate_batch_disable_fallbacks_surfaces_owning_provider_error():
router = litellm.Router(
model_list=[
{
"model_name": "owning-model",
"litellm_params": {
"model": "openai/gpt-4o-mini",
"api_key": "sk-owning",
},
},
{
"model_name": "fallback-model",
"litellm_params": {
"model": "azure/gpt-4o-mini",
"api_key": "sk-fallback",
"api_base": "https://fallback.openai.azure.com",
"api_version": "2024-08-01-preview",
},
},
],
fallbacks=[{"owning-model": ["fallback-model"]}],
num_retries=0,
)
owning_provider_error = litellm.BadRequestError(
message="completion_window must be one of: 24h",
model="openai/gpt-4o-mini",
llm_provider="openai",
)
mock_create = AsyncMock(side_effect=owning_provider_error)
with patch.object(router, "_acreate_batch", mock_create):
with pytest.raises(litellm.BadRequestError, match="24h"):
await router.acreate_batch(
model="owning-model",
input_file_id="file-owned-by-openai",
endpoint="/v1/chat/completions",
completion_window="5m",
disable_fallbacks=True,
)
mock_create.assert_awaited_once()
assert mock_create.call_args.kwargs["model"] == "owning-model"
@pytest.mark.asyncio
async def test_acreate_batch_request_bedrock_tags_override_deployment_tags():
import httpx