mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-15 23:31:29 +00:00
fix(proxy/batches): fail closed with 503 when the managed-file lookup errors
A lookup exception previously fell back to dispatching the unresolved unified token, which defeats the fail-closed guarantee: the token still reaches the provider and can hit the same publishers-segment IndexError the resolution prevents. Treat a lookup error like the missing-row case and fail closed, but with a retryable 503 since the condition is transient. No-database and no-storage_url rows still fall back unchanged
This commit is contained in:
parent
18dd984902
commit
891c6e4123
2 changed files with 19 additions and 12 deletions
|
|
@ -49,11 +49,12 @@ async def _resolve_managed_input_file_storage_url(input_file_id: str) -> "str |
|
|||
|
||||
Provider batch handlers (e.g. Vertex AI, which parses a `publishers/`
|
||||
segment out of the file URI) need a real storage location; the opaque
|
||||
unified token crashes them. Returns None when there is no database, the
|
||||
lookup fails, or the row has no storage_url yet, so callers fall back to
|
||||
the original id (which the managed-files deployment hook can still map).
|
||||
Raises a 404 when no managed-file row exists, since the token cannot be
|
||||
resolved and dispatching it would crash the provider.
|
||||
unified token crashes them. Returns None only when there is no database or
|
||||
the row has no storage_url yet, so callers fall back to the original id
|
||||
(which the managed-files deployment hook can still map). Fails closed
|
||||
rather than dispatch a token that cannot be resolved: 404 when no
|
||||
managed-file row exists, 503 when the lookup itself errors so the caller
|
||||
can retry.
|
||||
"""
|
||||
from litellm.proxy.proxy_server import prisma_client
|
||||
|
||||
|
|
@ -63,7 +64,10 @@ async def _resolve_managed_input_file_storage_url(input_file_id: str) -> "str |
|
|||
db_file = await ManagedFileRepository(prisma_client).table.find_first(where={"unified_file_id": input_file_id})
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.warning("create_batch: managed file lookup failed for %s: %s", input_file_id, e)
|
||||
return None
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail={"error": "Could not resolve managed file; please retry"},
|
||||
)
|
||||
if db_file is None:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
|
|
|
|||
|
|
@ -561,10 +561,10 @@ async def test_create__unified_file_id_resolves_real_storage_url(harness):
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create__unified_file_id_db_error_falls_back_to_raw_id(harness):
|
||||
"""A lookup failure must not abort batch creation. Resolution is best-effort
|
||||
crash prevention, so on a database error it falls back to dispatching the
|
||||
original id, which the managed-files deployment hook can still map."""
|
||||
async def test_create__unified_file_id_db_error_fails_closed_503(harness):
|
||||
"""A lookup error leaves the token unresolved, so it fails closed with a
|
||||
retryable 503 rather than dispatching the opaque id into the provider crash
|
||||
it cannot parse. Nothing is dispatched."""
|
||||
set_body(
|
||||
harness,
|
||||
{
|
||||
|
|
@ -585,9 +585,12 @@ async def test_create__unified_file_id_db_error_falls_back_to_raw_id(harness):
|
|||
patch.object(proxy_server, "prisma_client", MagicMock()),
|
||||
patch.object(endpoints, "ManagedFileRepository", fake_repo_cls),
|
||||
):
|
||||
await call_create(harness)
|
||||
with pytest.raises(ProxyException) as exc:
|
||||
await call_create(harness)
|
||||
|
||||
assert harness.router_kwargs()["input_file_id"] == "litellm_proxy_unified_id"
|
||||
assert exc.value.code == "503"
|
||||
harness.router_acreate.assert_not_called()
|
||||
harness.litellm_acreate.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue