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
This commit is contained in:
ryan-crabbe-berri 2026-07-27 12:37:25 -07:00
parent 42b5ea7ff7
commit 90ba89e1cc

View file

@ -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 $$;