fix(hasura): make 1741520400001 teams_name_unique migration idempotent#46
Merged
fix(hasura): make 1741520400001 teams_name_unique migration idempotent#46
Conversation
The migration was failing on every environment where the constraint had already been created, with: cannot drop index teams_name_unique because constraint teams_name_unique on table teams requires it The original script did a blind `DROP INDEX IF EXISTS` followed by `ADD CONSTRAINT`, which breaks when the constraint backs the index (the constraint owns the index, so DROP INDEX is rejected). This made the ArgoCD `hasura-migrations-job` PostSync hook fail on every sync and blocked feature 011 from deploying. Replace the two statements with a DO block that branches on current state: (a) expression index exists alone → DROP INDEX, ADD CONSTRAINT (b) constraint exists → no-op (c) neither exists → ADD CONSTRAINT Also guard the pre-existing name-normalisation UPDATE against a duplicate in cases where two rows normalise to the same value — the UPDATE itself was blowing up on unique-violation before the new constraint path even ran. Verified locally against state (b): migrate apply succeeds in <1 s and `migrate status` shows every migration Present/Present. Case (a) is reachable on fresh environments where the previous migration hadn't been applied; the branch logic is a straight DROP INDEX + ADD CONSTRAINT there which mirrors the original intent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
yasirali179
approved these changes
Apr 21, 2026
akshaykumar2505
approved these changes
Apr 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Unblocks the ArgoCD
hasura-migrations-jobPostSync hook, which has been failing on every sync and blocks all future Synmetrix deploys — including the recently merged Model Management API (#45).The migration was previously:
This crashes on any environment where the constraint was already created (locally on retry, or in the intermediate state after a partial apply):
DROP INDEXrefuses to drop an index that backs a UNIQUE constraint — the constraint owns the index.Fix
Replace the two blind statements with a
DOblock that branches on the current DB state and short-circuits when the desired end state already holds:teams_name_uniqueexists without a constraintDROP INDEXthenADD CONSTRAINTteams_name_uniquealready presentADD CONSTRAINTDetected via
pg_constraint+pg_indexeslookups rather than bare SQL statements.Also guarded
The pre-existing
UPDATE public.teams SET name = lower(trim(name)) …was itself failing with a duplicate-key violation on environments where two rows normalize to the same value ("Default team"+"default team"is a real case observed on the dev cluster and locally). The UPDATE now skips rows whose normalized form already exists in another row. The constraint is case-sensitive on the exact stored string, so the two rows coexist under the new constraint and the application (which always writeslower(trim(…))) only ever writes the normalized form going forward.Test plan
migrate statusshows every migration Present/Present.node --teston services/cubejs + services/actions: 475 / 479 pass (the 4 pre-existing unrelated failures unchanged).scripts/lint-error-codes.mjs: green.State (c) follows the direct
ADD CONSTRAINTpath — trivially correct.State (a) reproduces the original forward intent —
DROP INDEX+ADD CONSTRAINT— and was the path the old migration was already trying to run; it just needed to be gated so it doesn't run in state (b).Not in scope: fixing the symmetric bug in
down.sql(cannot recreate the expression index while duplicate normalized values exist). That path is only hit during intentional rollbacks and is not on the deploy critical path.🤖 Generated with Claude Code