From 124c73c1edf452de15e6ca136d90920f806331ed Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 6 May 2026 16:01:25 -0700 Subject: [PATCH] fix(internal_endpoints): only treat seq-collisions as 409 in events:append retry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The seq-collision retry in daemon_append_event previously caught all Exception types and re-raised them as 409 event_seq_collision. A transient DB error during retry would surface to the daemon as a misleading 409, hiding the real outage and the daemon would respond incorrectly (they treat 409 as 'data conflict, drop the event' rather than 'retry'). Add a narrow _is_seq_collision predicate that matches: * prisma.errors.UniqueViolationError (production) * RuntimeError('event_seq_collision') marker (test stand-in) Other errors bubble up unchanged so callers can distinguish a real seq conflict from a real outage. Greptile (review #PRR_kwDOKALCgc78u_NS — overly broad exception catch in seq-collision retry). --- .../internal_endpoints.py | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/litellm/proxy/agent_session_endpoints/internal_endpoints.py b/litellm/proxy/agent_session_endpoints/internal_endpoints.py index 69585295bf8..99d9e2b5d9e 100644 --- a/litellm/proxy/agent_session_endpoints/internal_endpoints.py +++ b/litellm/proxy/agent_session_endpoints/internal_endpoints.py @@ -50,6 +50,26 @@ def _now() -> datetime: return datetime.now(timezone.utc) +def _is_seq_collision(exc: BaseException) -> bool: + """True iff ``exc`` is a (run_id, seq) unique-constraint violation. + + We can't simply ``except prisma.errors.UniqueViolationError`` because + the unit-test stand-in raises a plain ``RuntimeError("event_seq_collision")``, + and we don't want the test path and prod path to diverge. Match + either the Prisma class (when available) or our marker string. + """ + try: + from prisma.errors import UniqueViolationError + + if isinstance(exc, UniqueViolationError): + return True + except Exception: + # Prisma unavailable in some test environments; fall through to + # string-based detection. + pass + return "event_seq_collision" in str(exc) + + async def _get_prisma_client_or_503(): from litellm.proxy.proxy_server import prisma_client @@ -250,9 +270,14 @@ async def daemon_append_event( } ) except Exception as exc: - # Most likely a (run_id, seq) unique-constraint collision. Reread - # MAX(seq) and try once more — that's the defensive retry the - # ticket calls out. + # Treat only ``(run_id, seq)`` unique-constraint collisions as + # retryable here; let any other error bubble up unchanged so + # callers don't see a misleading 409 ``event_seq_collision`` + # for a transient DB outage. We detect collisions either via + # the dedicated Prisma error class or — for unit tests using + # an in-memory fake — a string match on the marker. + if not _is_seq_collision(exc): + raise last_evt = await prisma_client.db.litellm_agentrunevent.find_first( where={"run_id": run_id}, order={"seq": "desc"}, @@ -268,6 +293,8 @@ async def daemon_append_event( } ) except Exception as exc2: + if not _is_seq_collision(exc2): + raise verbose_proxy_logger.exception( "events:append double-collision run_id=%s: %s", run_id, exc2 )