From 90ba89e1cc85dff873d61b5d7d12a5101e183fce Mon Sep 17 00:00:00 2001 From: ryan-crabbe-berri Date: Mon, 27 Jul 2026 12:37:25 -0700 Subject: [PATCH] fix(migration): add user FK as NOT VALID so no existing rows are touched Self-hosted databases can contain keys whose user_id references a user deleted before the constraint existed, or used as free-form attribution. Nulling those rows was irreversible data mutation and the validating ALTER TABLE could fail a deploy. NOT VALID adds the constraint without reading a single existing row, enforcing only new writes; a best-effort VALIDATE then upgrades it to fully valid on clean databases and quietly leaves it NOT VALID where orphans exist. The migration can no longer fail or modify data under any database state --- .../migration.sql | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/litellm-proxy-extras/litellm_proxy_extras/migrations/20260727000000_add_verification_token_user_fkey/migration.sql b/litellm-proxy-extras/litellm_proxy_extras/migrations/20260727000000_add_verification_token_user_fkey/migration.sql index fed756cd334..18dfb895caf 100644 --- a/litellm-proxy-extras/litellm_proxy_extras/migrations/20260727000000_add_verification_token_user_fkey/migration.sql +++ b/litellm-proxy-extras/litellm_proxy_extras/migrations/20260727000000_add_verification_token_user_fkey/migration.sql @@ -1,15 +1,23 @@ --- Null out user_ids that reference users that no longer exist; the foreign key --- below cannot be added over them, and ON DELETE SET NULL would have produced --- the same rows had the constraint existed when those users were deleted -UPDATE "LiteLLM_VerificationToken" vt -SET "user_id" = NULL -WHERE vt."user_id" IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM "LiteLLM_UserTable" u WHERE u."user_id" = vt."user_id"); - -- AddForeignKey +-- NOT VALID so no existing row is touched or judged: keys whose user_id points +-- at a user that no longer existed before this migration keep their value, and +-- the constraint only enforces new INSERTs and UPDATEs of user_id. DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'LiteLLM_VerificationToken_user_id_fkey') THEN - ALTER TABLE "LiteLLM_VerificationToken" ADD CONSTRAINT "LiteLLM_VerificationToken_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "LiteLLM_UserTable"("user_id") ON DELETE SET NULL ON UPDATE CASCADE; + ALTER TABLE "LiteLLM_VerificationToken" ADD CONSTRAINT "LiteLLM_VerificationToken_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "LiteLLM_UserTable"("user_id") ON DELETE SET NULL ON UPDATE CASCADE NOT VALID; END IF; END $$; + +-- Best-effort validation: on databases with no orphaned user_ids (the normal +-- case; user deletion removes the user's keys) this marks the constraint fully +-- valid. Where orphans exist the constraint simply stays NOT VALID and keeps +-- enforcing go-forward writes; the migration never fails and never mutates data. +DO $$ +BEGIN + BEGIN + ALTER TABLE "LiteLLM_VerificationToken" VALIDATE CONSTRAINT "LiteLLM_VerificationToken_user_id_fkey"; + EXCEPTION WHEN foreign_key_violation THEN + RAISE NOTICE 'LiteLLM_VerificationToken has user_ids referencing missing users; constraint left NOT VALID'; + END; +END $$;