multica-ai/multica · critical
apply migration %q: %w
Error message
apply migration %q: %w
What it means
Returned when conn.Exec of the migration SQL file itself fails while applying it. The migration runs on the loop's pinned connection holding the migration advisory lock, so a failure means the SQL in the .sql file was rejected by Postgres (syntax, dependency, permission, or existing object).
Source
Thrown at server/cmd/migrate/main.go:441
if err != nil {
return fmt.Errorf("read migration %q: %w", file, err)
}
// Run any pre-migration hook before the SQL file. Hooks
// receive the *pgxpool.Pool (not the loop's pinned conn), so
// they can acquire other session-level locks without
// colliding with migrationAdvisoryLockKey. Hook failures
// abort the run before schema_migrations is updated, so the
// same version retries cleanly on the next invocation.
if hook, ok := opts.Hooks[version]; ok && hook != nil {
slog.Info("running pre-migration hook", "version", version, "direction", opts.Direction)
if err := hook(ctx, pool); err != nil {
return fmt.Errorf("pre-migration hook for %q (%s): %w", version, opts.Direction, err)
}
}
if _, err := conn.Exec(ctx, string(sql)); err != nil {
return fmt.Errorf("apply migration %q: %w", file, err)
}
if opts.Direction == "up" {
_, err = conn.Exec(ctx, insertSQL, version)
} else {
_, err = conn.Exec(ctx, deleteSQL, version)
}
if err != nil {
return fmt.Errorf("record migration %q: %w", version, err)
}
fmt.Printf(" %s %s\n", opts.Direction, version)
}
return nil
}
// quoteQualifiedIdentifier safely quotes either an unqualified tableView on GitHub (pinned to 2c0912b6ec)
Solutions
- Read the wrapped Postgres error in the %w chain — it names the exact statement-level failure (relation already exists, syntax error, etc.).
- If the object already exists because the migration partially applied in a prior failed run, wrap destructive/creative statements in IF (NOT) EXISTS or roll back the partial objects by hand, then re-run.
- If this is an edited already-recorded migration, restore the original file or write a NEW migration instead — never edit an applied version.
- Re-run `migrate`; schema_migrations was not updated for this version, so it retries.
Example fix
-- before: fails on re-run after a partial failure CREATE TABLE issue_links (...); -- after: idempotent so a clean retry succeeds CREATE TABLE IF NOT EXISTS issue_links (...);
Defensive patterns
Strategy: validation
Validate before calling
-- Dry-run each new migration on a schema snapshot (e.g. via a CI step that -- clones prod schema and applies pending files) before it reaches production, -- so apply failures surface in CI, not during deploy.
Try / catch
err := runMigrations(ctx, pool, opts)
if err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) {
switch pgErr.Code {
case "42P07", "42710": // duplicate_table, duplicate_object
log.Printf("object already exists; migration may have partially applied: %v", pgErr.Message)
case "42703", "42P01": // undefined column/table
log.Printf("ordering problem: references an object created later: %v", pgErr.Message)
}
}
return err
} Prevention
- Never edit an already-applied migration; always add a new file.
- Prefer IF NOT EXISTS / IF EXISTS in DDL so retries after partial failures succeed.
- Run pending migrations against a prod-schema clone in CI before deploy.
When it happens
Trigger: Applying a migration file whose SQL fails: CREATE TABLE on an existing name, invalid syntax, reference to a column/table created in a later migration, insufficient privileges, or a statement cancelled by statement_timeout.
Common situations: Editing an already-applied migration file (checksum/content drift so it no longer matches the schema), splitting one migration into two and running them out of order, running migrations with a role that lacks CREATE privilege, or a concurrent process having created the same object.
Related errors
- check migration %q: %w
- pre-migration hook for %q (%s): %w
- record migration %q: %w
- scan task_usage time range: %w
- stamp watermark: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/99d8d64e15f6087a.
Report an issue: GitHub.