n8n-io/n8n · error · TypeORMError

OnUpdateType "${relation.onUpdate}" is not valid for ${drive

Error message

OnUpdateType "${relation.onUpdate}" is not valid for ${driver.options.type}!

What it means

During entity metadata validation TypeORM cross-checks each relation's `onUpdate` referential action against the active driver's `supportedOnUpdateTypes` list. If the driver does not advertise the requested action the mapping is rejected outright rather than silently ignored, so an unsupported cascade cannot ship to the schema. This runs at schema-build time (DataSource.initialize / synchronize).

Source

Thrown at packages/@n8n/typeorm/src/metadata-builder/EntityMetadataValidator.ts:171

		entityMetadata.relations.forEach((relation) => {
			// check OnDeleteTypes
			if (
				driver.supportedOnDeleteTypes &&
				relation.onDelete &&
				!driver.supportedOnDeleteTypes.includes(relation.onDelete)
			) {
				throw new TypeORMError(
					`OnDeleteType "${relation.onDelete}" is not supported for ${driver.options.type}!`,
				);
			}

			// check OnUpdateTypes
			if (
				driver.supportedOnUpdateTypes &&
				relation.onUpdate &&
				!driver.supportedOnUpdateTypes.includes(relation.onUpdate)
			) {
				throw new TypeORMError(
					`OnUpdateType "${relation.onUpdate}" is not valid for ${driver.options.type}!`,
				);
			}

			// check join tables:
			// using JoinTable is possible only on one side of the many-to-many relation
			// todo(dima): fix
			// if (relation.joinTable) {
			//     if (!relation.isManyToMany)
			//         throw new UsingJoinTableIsNotAllowedError(entityMetadata, relation);
			//     // if there is inverse side of the relation, then check if it does not have join table too
			//     if (relation.hasInverseSide && relation.inverseRelation.joinTable)
			//         throw new UsingJoinTableOnlyOnOneSideAllowedError(entityMetadata, relation);
			// }
			// check join columns:
			// using JoinColumn is possible only on one side of the relation and on one-to-one, many-to-one relation types
			// first check if relation is one-to-one or many-to-one
			// todo(dima): fix

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Drop `onUpdate` from the relation decorator and rely on the database default; this is the right call when targeting SQLite.
  2. Match the DB engine: use Postgres/MySQL in the failing environment so the action is supported.
  3. If you must keep the cascade, define it in a raw migration (`FOREIGN KEY ... ON UPDATE CASCADE`) instead of the decorator.

Example fix

// before
@ManyToOne(() => User, { onUpdate: 'CASCADE' })
user: User;

// after
@ManyToOne(() => User)
user: User;
Defensive patterns

Strategy: validation

Validate before calling

// Before initializing, confirm the driver actually supports the onUpdate action
const supported = dataSource.driver.supportedOnUpdateTypes ?? [];
const want = 'CASCADE'; // the action declared in your decorator
if (!supported.includes(want)) {
  throw new Error(`Driver ${dataSource.options.type} does not support onUpdate='${want}'; supported: ${supported.join(',')}`);
}

Try / catch

try { await dataSource.initialize(); } catch (e) { if (e instanceof TypeORMError && /OnUpdateType/.test(e.message)) { /* surface a config-level message naming the driver + relation */ } throw e; }

Prevention

When it happens

Trigger: Declaring `@ManyToOne(() => User, { onUpdate: 'CASCADE' })` (or any @OneToOne/@ManyToMany join column with `onUpdate`) while the DataSource is bound to SQLite, whose driver exposes an empty/limited `supportedOnUpdateTypes`. Also triggered by actions like 'SET NULL' or 'RESTRICT' on a driver that does not list them.

Common situations: Running Postgres locally with ON UPDATE cascades, then pointing CI at an in-memory sqlite3 DB. Upgrading the vendored typeorm to a version that tightened `supportedOnUpdateTypes`. Copying a relation decorator from a Postgres entity into a SQLite test entity.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/99c803bcb928b1ee. Report an issue: GitHub.