drizzle-team/drizzle-orm · error · Error
The '${table1.name}' and '${table2.name}' tables have not nu
Error message
The '${table1.name}' and '${table2.name}' tables have not null foreign keys. You can't seed cyclic tables with not null foreign key columns. What it means
When two tables reference each other cyclically and BOTH sides of the cycle have NOT NULL foreign-key columns, drizzle-seed cannot insert either table first: each row requires a valid non-null FK value from the other table that does not yet exist. The cyclicTablesCompare comparator detects this deadlock and throws.
Source
Thrown at drizzle-seed/src/services/SeedService.ts:356
cyclicTablesCompare = (
table1: Table,
table2: Table,
relation: Relation & { isCyclic: boolean },
reverseRelation: Relation & { isCyclic: boolean } | undefined,
) => {
// TODO: revise
const hasTable1NotNullColumns = relation.columns.some((colIName) =>
table1.columns.find((colJ) => colJ.name === colIName)?.notNull === true
);
if (reverseRelation !== undefined) {
const hasTable2NotNullColumns = reverseRelation.columns.some((colIName) =>
table2.columns.find((colJ) => colJ.name === colIName)?.notNull === true
);
if (hasTable1NotNullColumns && hasTable2NotNullColumns) {
throw new Error(
`The '${table1.name}' and '${table2.name}' tables have not null foreign keys. You can't seed cyclic tables with not null foreign key columns.`,
);
}
if (hasTable1NotNullColumns) return 1;
else if (hasTable2NotNullColumns) return -1;
return 0;
}
if (hasTable1NotNullColumns) {
return 1;
}
return 0;
// if (hasTable1NotNullColumns) return 1;
// else if (hasTable2NotNullColumns) return -1;
};
View on GitHub (pinned to b7862528fd)
Solutions
- Make at least one side of the cycle nullable so drizzle-seed can insert that table first, back-fill, then update.
- Use database-level deferred FK constraints (Postgres DEFERRABLE INITIALLY DEFERRED) and set the column nullable for seeding.
- Break the cycle by seeding one table with a refined generator that supplies a placeholder/valid value, then seed the other.
Example fix
// before — mutual NOT NULL FKs
users: { profileId: integer().notNull().references(() => profiles.id) }
profiles: { userId: integer().notNull().references(() => users.id) }
// after — make one side nullable
users: { profileId: integer().references(() => profiles.id) } Defensive patterns
Strategy: validation
Validate before calling
// Detect mutual NOT NULL FK cycles before seeding.
function hasMutualNotNullCycle(
relations: Array<{ table: string; refTable: string; columns: string[]; isCyclic: boolean }>,
columnNotNull: (table: string, col: string) => boolean
): boolean {
for (const r of relations) {
if (!r.isCyclic) continue;
const reverse = relations.find((x) => x.table === r.refTable && x.refTable === r.table);
if (!reverse) continue;
const sideA = r.columns.some((c) => columnNotNull(r.table, c));
const sideB = reverse.columns.some((c) => columnNotNull(reverse.table, c));
if (sideA && sideB) return true;
}
return false;
} Prevention
- Always make at least one side of a cyclic FK nullable.
- Use Postgres DEFERRABLE INITIALLY DEFERRED for cyclic constraints in production.
- Review cyclic relationships during schema design for seeding feasibility.
When it happens
Trigger: Two tables A and B where A has a NOT NULL FK to B and B has a NOT NULL FK to A (mutual mandatory dependency); the seeder needs to order them but neither can go first.
Common situations: Modeling bidirectional relationships with mandatory links (e.g. User.profileId NOT NULL and Profile.userId NOT NULL); schema where a deferred/nullable FK was accidentally made NOT NULL.
Related errors
- Column '${col.name}' has not null contraint, and you didn't
- There is not enough information to infer relation "${sourceT
- ${reason}. You can't specify "${fkTableName}" as parameter i
- Table '${tableGen.tableName}' does not have primary or (uniq
- unsupported dialect
AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03).
Data as JSON: /data/errors/cb9299b4449504ef.json.
Report an issue: GitHub.