mcpField
E
ecto-constraint-debug

ecto-constraint-debug

github.com/oliver-kriskaDevelopment57144 installsUpdated 6d ago
Repository

About ecto-constraint-debug

ecto-constraint-debug is a debugging skill for Elixir developers investigating Ecto constraint errors. It guides diagnosis from the reported constraint name through migrations, schema handling, and all insert paths, including possible race conditions.

Key features

  1. 01Parse constraint error details
  2. 02Compare migrations with schema constraints
  3. 03Trace insert and update paths
  4. 04Investigate likely race conditions
  5. 05Apply fixes by constraint type

Use cases

  1. 01Diagnose unique constraint violations
  2. 02Find causes of foreign key errors
  3. 03Investigate changeset constraint failures
  4. 04Check concurrent writes after validation passes

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix --skill ecto-constraint-debug

After installing, type/ecto-constraint-debugin Claude Code to confirm it loaded.

Bundled filesreferences/constraint-patterns.md

Details

From the project README

Ecto Constraint Debugging

Ash projects: Ash surfaces DB constraints through its own error DSL. Use the ash-framework skill — mix usage_rules.search_docs "constraint" -p ash_postgres.

Systematic approach to diagnosing constraint violations. Load when you see Ecto.ConstraintError, unique_constraint, foreign_key_constraint, or constraint-related changeset errors.

Iron Laws

  1. READ THE CONSTRAINT NAME — The constraint name (e.g., links_url_index) tells you exactly which index/constraint failed. Parse it from the error message first
  2. CHECK MIGRATION BEFORE CODE — Verify the constraint definition in priv/repo/migrations/ matches what the schema expects
  3. TRACE ALL INSERT PATHS — Find every code path that inserts into the constrained table. The bug is often in a path you didn't consider
  4. RACE CONDITION UNTIL PROVEN OTHERWISE — If validation passes but constraint fails, assume concurrent inserts until you prove a single-request cause

Step-by-Step Debugging

Step 1: Parse the Error

Extract from the error message:

  • Constraint name (e.g., users_email_index)
  • Table name (e.g., users)
  • Operation (insert, update, or delete)
  • Conflicting values (if available in logs)
Step 2: Find the Migration

Use Grep to search for the constraint name in priv/repo/migrations/. Also check for create unique_index, create index, add constraint.

Verify: Does the migration constraint match the schema's unique_constraint/3 or foreign_key_constraint/3 call?

Step 3: Find the Schema

Use Grep to find constraint handling in changesets (unique_constraint, foreign_key_constraint, check_constraint) in lib/.

Step 4: Trace Insert Paths

Find ALL callers that insert/update this schema:

Use Grep to find all insert/update paths (Repo.insert, Repo.update, Repo.insert_all, cast_assoc) in lib/.

Step 5: Identify the Cause
SymptomLikely CauseFix Pattern
Same user triggers twiceRace condition (double-click, retry)Upsert with on_conflict
Multiple parents share childcast_assoc doesn't dedup across changesetsDedup before building changesets
Concurrent API requestsMissing transaction isolationWrap in Repo.transaction or use upsert
Migration added constraint to existing dataData violates new constraintBackfill or clean data first
Step 6: Apply Fix

See ${CLAUDE_SKILL_DIR}/references/constraint-patterns.md for detailed fix patterns.

Quick Fixes by Constraint Type

Unique violation → Upsert: Repo.insert(changeset, on_conflict: :replace_all, conflict_target: [:field])

Foreign key violation → Check: Does the referenced record exist? Was it deleted concurrently?

Check constraint → Validate: Does the value satisfy the constraint condition?

References

  • ${CLAUDE_SKILL_DIR}/references/constraint-patterns.md - Detailed patterns for each constraint type

Comments

Markdown supported