diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20260429000000_add_scheduled_tasks/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20260429000000_add_scheduled_tasks/migration.sql index 919ae5ad431..9a564b4a05b 100644 --- a/litellm-proxy-extras/litellm_proxy_extras/migrations/20260429000000_add_scheduled_tasks/migration.sql +++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20260429000000_add_scheduled_tasks/migration.sql @@ -40,13 +40,6 @@ CREATE INDEX "LiteLLM_ScheduledTaskTable_team_id_idx" CREATE INDEX "LiteLLM_ScheduledTaskTable_agent_id_status_idx" ON "LiteLLM_ScheduledTaskTable" ("agent_id", "status"); --- AddForeignKey -ALTER TABLE "LiteLLM_ScheduledTaskTable" - ADD CONSTRAINT "LiteLLM_ScheduledTaskTable_owner_token_fkey" - FOREIGN KEY ("owner_token") - REFERENCES "LiteLLM_VerificationToken" ("token") - ON DELETE CASCADE ON UPDATE CASCADE; - -- Hand-appended (Prisma cannot express partial indexes or CHECK constraints): -- Partial index over rows the ticker actually scans. diff --git a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma index fc6cb6b04d9..24334fc04c1 100644 --- a/litellm-proxy-extras/litellm_proxy_extras/schema.prisma +++ b/litellm-proxy-extras/litellm_proxy_extras/schema.prisma @@ -410,7 +410,6 @@ model LiteLLM_VerificationToken { litellm_project_table LiteLLM_ProjectTable? @relation(fields: [project_id], references: [project_id]) object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id]) jwt_key_mappings LiteLLM_JWTKeyMapping[] - scheduled_tasks LiteLLM_ScheduledTaskTable[] // SELECT COUNT(*) FROM (SELECT "public"."LiteLLM_VerificationToken"."token" FROM "public"."LiteLLM_VerificationToken" WHERE ("public"."LiteLLM_VerificationToken"."user_id" = $1 AND ("public"."LiteLLM_VerificationToken"."team_id" IS NULL OR "public"."LiteLLM_VerificationToken"."team_id" <> $2)) OFFSET $3 ) AS "sub" // SELECT ... FROM "public"."LiteLLM_VerificationToken" WHERE "public"."LiteLLM_VerificationToken"."user_id" = $1 OFFSET $2 @@ -1295,8 +1294,12 @@ model LiteLLM_AdaptiveRouterSession { model LiteLLM_ScheduledTaskTable { task_id String @id @default(uuid()) + // owner_token holds the hashed verification token of the calling key. + // Intentionally not declared as a foreign key — the proxy's master key + // has no row in LiteLLM_VerificationToken, so a hard FK would block any + // master-key caller from creating a task. Cleanup of orphaned rows is + // an operator responsibility. owner_token String - owner_key LiteLLM_VerificationToken @relation(fields: [owner_token], references: [token], onDelete: Cascade) user_id String? team_id String? agent_id String? diff --git a/litellm/proxy/scheduled_tasks/store.py b/litellm/proxy/scheduled_tasks/store.py index 382f469c8fe..f8099380328 100644 --- a/litellm/proxy/scheduled_tasks/store.py +++ b/litellm/proxy/scheduled_tasks/store.py @@ -77,9 +77,7 @@ async def create_task( ) -> Any: return await prisma_client.db.litellm_scheduledtasktable.create( data={ - # Prisma exposes the FK via the relation field (`owner_key`), - # not the scalar column. Use connect to satisfy the input type. - "owner_key": {"connect": {"token": owner_token}}, + "owner_token": owner_token, "user_id": user_id, "team_id": team_id, "agent_id": agent_id, diff --git a/litellm/proxy/schema.prisma b/litellm/proxy/schema.prisma index fc6cb6b04d9..24334fc04c1 100644 --- a/litellm/proxy/schema.prisma +++ b/litellm/proxy/schema.prisma @@ -410,7 +410,6 @@ model LiteLLM_VerificationToken { litellm_project_table LiteLLM_ProjectTable? @relation(fields: [project_id], references: [project_id]) object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id]) jwt_key_mappings LiteLLM_JWTKeyMapping[] - scheduled_tasks LiteLLM_ScheduledTaskTable[] // SELECT COUNT(*) FROM (SELECT "public"."LiteLLM_VerificationToken"."token" FROM "public"."LiteLLM_VerificationToken" WHERE ("public"."LiteLLM_VerificationToken"."user_id" = $1 AND ("public"."LiteLLM_VerificationToken"."team_id" IS NULL OR "public"."LiteLLM_VerificationToken"."team_id" <> $2)) OFFSET $3 ) AS "sub" // SELECT ... FROM "public"."LiteLLM_VerificationToken" WHERE "public"."LiteLLM_VerificationToken"."user_id" = $1 OFFSET $2 @@ -1295,8 +1294,12 @@ model LiteLLM_AdaptiveRouterSession { model LiteLLM_ScheduledTaskTable { task_id String @id @default(uuid()) + // owner_token holds the hashed verification token of the calling key. + // Intentionally not declared as a foreign key — the proxy's master key + // has no row in LiteLLM_VerificationToken, so a hard FK would block any + // master-key caller from creating a task. Cleanup of orphaned rows is + // an operator responsibility. owner_token String - owner_key LiteLLM_VerificationToken @relation(fields: [owner_token], references: [token], onDelete: Cascade) user_id String? team_id String? agent_id String? diff --git a/schema.prisma b/schema.prisma index fc6cb6b04d9..24334fc04c1 100644 --- a/schema.prisma +++ b/schema.prisma @@ -410,7 +410,6 @@ model LiteLLM_VerificationToken { litellm_project_table LiteLLM_ProjectTable? @relation(fields: [project_id], references: [project_id]) object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id]) jwt_key_mappings LiteLLM_JWTKeyMapping[] - scheduled_tasks LiteLLM_ScheduledTaskTable[] // SELECT COUNT(*) FROM (SELECT "public"."LiteLLM_VerificationToken"."token" FROM "public"."LiteLLM_VerificationToken" WHERE ("public"."LiteLLM_VerificationToken"."user_id" = $1 AND ("public"."LiteLLM_VerificationToken"."team_id" IS NULL OR "public"."LiteLLM_VerificationToken"."team_id" <> $2)) OFFSET $3 ) AS "sub" // SELECT ... FROM "public"."LiteLLM_VerificationToken" WHERE "public"."LiteLLM_VerificationToken"."user_id" = $1 OFFSET $2 @@ -1295,8 +1294,12 @@ model LiteLLM_AdaptiveRouterSession { model LiteLLM_ScheduledTaskTable { task_id String @id @default(uuid()) + // owner_token holds the hashed verification token of the calling key. + // Intentionally not declared as a foreign key — the proxy's master key + // has no row in LiteLLM_VerificationToken, so a hard FK would block any + // master-key caller from creating a task. Cleanup of orphaned rows is + // an operator responsibility. owner_token String - owner_key LiteLLM_VerificationToken @relation(fields: [owner_token], references: [token], onDelete: Cascade) user_id String? team_id String? agent_id String?