remix-run/remix · error · Error
Duplicate migration id: {migration.id}
Error message
Duplicate migration id: {migration.id} What it means
createMigrationRegistry was initialized with two MigrationDescriptor entries sharing the same `id`. Since ids drive ordering and journal bookkeeping, duplicates are rejected eagerly at registry construction.
Source
Thrown at packages/data-table/src/lib/migrations/registry.ts:44
/**
* Creates an in-memory migration registry.
* @param initial Optional initial migration list.
* @returns A migration registry with duplicate-id protection.
* @example
* ```ts
* import { createMigrationRegistry } from 'remix/data-table/migrations'
*
* let registry = createMigrationRegistry()
* registry.register({ id, name, up, down })
* ```
*/
export function createMigrationRegistry(initial: MigrationDescriptor[] = []): MigrationRegistry {
let migrations = new Map<string, MigrationDescriptor>()
for (let migration of initial) {
if (migrations.has(migration.id)) {
throw new Error('Duplicate migration id: ' + migration.id)
}
migrations.set(migration.id, migration)
}
return {
register(migration: MigrationDescriptor) {
if (migrations.has(migration.id)) {
throw new Error('Duplicate migration id: ' + migration.id)
}
migrations.set(migration.id, migration)
},
list() {
return sortMigrations(Array.from(migrations.values()))
},
}
}View on GitHub (pinned to 9696913134)
Solutions
- Inspect the descriptors passed as `initial` and remove or rename the duplicate id.
- Check for the same migration directory being scanned twice by your loader.
- If two distinct migrations share a timestamp-second id, regenerate one with a later timestamp and update the journal.
Example fix
// before
createMigrationRegistry([
{ id: '20240101123045', name: 'create_users', ... },
{ id: '20240101123045', name: 'add_index', ... },
])
// after
createMigrationRegistry([
{ id: '20240101123045', name: 'create_users', ... },
{ id: '20240101123046', name: 'add_index', ... },
]) Defensive patterns
Strategy: validation
Validate before calling
let ids = descriptors.map((m) => m.id)
if (new Set(ids).size !== ids.length) {
let dup = ids.find((id, i) => ids.indexOf(id) !== i)
throw new Error('duplicate migration id in input: ' + dup)
} Type guard
function hasUniqueIds(migrations: MigrationDescriptor[]): boolean {
return new Set(migrations.map((m) => m.id)).size === migrations.length
} Try / catch
try {
let registry = createMigrationRegistry(all)
} catch (error) {
if (error instanceof Error && error.message.startsWith('Duplicate migration id')) {
// dedupe by id, keeping first, then retry
}
throw error
} Prevention
- Dedupe loaded descriptors by file path and id before constructing the registry.
- Treat duplicate ids in a migration set as a CI failure.
When it happens
Trigger: Passing an `initial` array (e.g. loaded module descriptors) to createMigrationRegistry where two entries have the same `id` string, often from loading the same directory twice or two migrations generated in the same second.
Common situations: Globbing migrations from overlapping directories; a rebase duplicating a migration file; two migrations created within the same timestamp second.
Related errors
- Duplicate migration id "{id}" inferred from directory "{dire
- expected promise to resolve, but it rejected with: ${stringi
- ${optionName} values must be package names. Received "${pack
- Cannot combine "to" and "step" migration options in the same
- Migration directory "{directoryName}" is missing up.sql
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/fd9a49591389fd6f.
Report an issue: GitHub.