From e39e1c8deaefe71d9ddea6025370939afaf98598 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 06:40:40 +0000 Subject: [PATCH] fix(proxy): take the write-slot advisory lock before member name checks Bugbot flagged that the member create path ran its name-collision check without any lock, so two concurrent creates of the same name could both pass. Take the same pg_advisory_xact_lock main takes at the top of the write transaction so member writes serialize before the checks run. --- .../proxy/management_endpoints/model_management_endpoints.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/litellm/proxy/management_endpoints/model_management_endpoints.py b/litellm/proxy/management_endpoints/model_management_endpoints.py index 340a0b427b9..4e27efad609 100644 --- a/litellm/proxy/management_endpoints/model_management_endpoints.py +++ b/litellm/proxy/management_endpoints/model_management_endpoints.py @@ -321,6 +321,10 @@ def _member_auto_router_marker_for_update( return incoming_params.model is None or incoming_params.model == _effective_model(None, existing.litellm_params) +AUTO_ROUTER_WRITE_SLOT_LOCK_KEY: Final = 5_872_301 +_WRITE_SLOT_LOCK_SQL: Final = "SELECT 1 AS locked FROM pg_advisory_xact_lock($1)" + + @asynccontextmanager async def _member_auto_router_write_slot( prisma_client: PrismaClient, @@ -345,6 +349,7 @@ async def _member_auto_router_write_slot( transaction_client: Final = _ModelTransactionClient.model_validate(prisma_client.db) async with transaction_client.tx(timeout=datetime.timedelta(seconds=30)) as tx_ctx: tables: Final[_TxModelTables] = tx_ctx + await tx_ctx.query_raw(_WRITE_SLOT_LOCK_SQL, AUTO_ROUTER_WRITE_SLOT_LOCK_KEY) config_rows: Final = () if llm_router is None else tuple(llm_router.config_deployments()) if member_write.model_id is not None: await tx_ctx.query_raw(