drizzle-team/drizzle-orm · error · Error

Table '${tableGen.tableName}' does not have primary or (uniq

Error message

Table '${tableGen.tableName}' does not have primary or (unique and notNull) column. Can't seed table with cyclic relation.

What it means

To seed cyclic tables, drizzle-seed must defer one side of the cycle and later update it. It needs a column to use as a stable identity key for that update — either a primary key, or a column that is both unique AND notNull. If a table in a cyclic relation has neither, filterCyclicTables throws because there is no reliable column to match deferred rows.

Source

Thrown at drizzle-seed/src/services/SeedService.ts:1124

	};

	filterCyclicTables = (tablesGenerators: ReturnType<typeof this.generatePossibleGenerators>) => {
		const filteredTablesGenerators = tablesGenerators.filter((tableGen) =>
			tableGen.columnsPossibleGenerators.some((columnGen) =>
				columnGen.isCyclic === true && columnGen.wasDefinedBefore === true
			)
		);

		const tablesUniqueNotNullColumn: { [tableName: string]: { uniqueNotNullColName: string } } = {};

		for (const [idx, tableGen] of filteredTablesGenerators.entries()) {
			const uniqueNotNullColName = filteredTablesGenerators[idx]!.columnsPossibleGenerators.find((colGen) =>
				colGen.primary === true
				|| (colGen.isUnique === true
					&& colGen.notNull === true)
			)?.columnName;
			if (uniqueNotNullColName === undefined) {
				throw new Error(
					`Table '${tableGen.tableName}' does not have primary or (unique and notNull) column. Can't seed table with cyclic relation.`,
				);
			}
			tablesUniqueNotNullColumn[tableGen.tableName] = { uniqueNotNullColName };

			filteredTablesGenerators[idx]!.columnsPossibleGenerators = tableGen.columnsPossibleGenerators.filter((colGen) =>
				(colGen.isCyclic === true && colGen.wasDefinedBefore === true) || colGen.columnName === uniqueNotNullColName
			).map((colGen) => {
				const newColGen = { ...colGen };
				newColGen.wasDefinedBefore = false;
				return newColGen;
			});
		}

		return { filteredTablesGenerators, tablesUniqueNotNullColumn };
	};

	generateTablesValues = async (

View on GitHub (pinned to b7862528fd)

Solutions

  1. Add a primary key column (e.g. an auto-incrementing id) to the table.
  2. Add a unique + notNull constraint to an existing column that can serve as the identity key.
  3. If the table is a pure junction, break the cycle by making one FK nullable so the table is no longer treated as cyclic.

Example fix

// before — junction table, no PK, part of cycle
export const links = pgTable('links', {
  aId: integer().references(() => a.id),
  bId: integer().references(() => b.id),
});
// after — add a primary key
export const links = pgTable('links', {
  id: serial('id').primaryKey(),
  aId: integer().references(() => a.id),
  bId: integer().references(() => b.id),
});
Defensive patterns

Strategy: validation

Validate before calling

// Verify every table in a cyclic relation has a PK or (unique && notNull) column.
function cyclicTablesHaveKey(
  tables: Array<{ name: string; columns: Array<{ name: string; primary: boolean; isUnique: boolean; notNull: boolean }> }>,
  cyclicTableNames: Set<string>
): string[] {
  const missing: string[] = [];
  for (const t of tables) {
    if (!cyclicTableNames.has(t.name)) continue;
    const hasKey = t.columns.some((c) => c.primary || (c.isUnique && c.notNull));
    if (!hasKey) missing.push(t.name);
  }
  return missing;
}

Prevention

When it happens

Trigger: A table participating in a cyclic FK relationship that has no primary key and no unique+notNull column; common in pure junction/link tables with only two nullable FK columns.

Common situations: Junction tables in many-to-many relationships that participate in a cycle; tables where the PK was accidentally removed or made non-unique during a migration.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /data/errors/51b60ab92ad6888a.json. Report an issue: GitHub.