remix-run/remix · error · Error
Unsupported operation kind
Error message
Unsupported operation kind
What it means
compileMysqlOperation is the exhaustive tail of a switch over operation.kind for the MySQL SQL compiler: it handles known kinds (insert, update, delete, upsert, etc.) and throws 'Unsupported operation kind' for anything else. Seeing it means an operation object reached the compiler with a kind the MySQL backend does not implement — usually a new/typo kind or a cross-backend operation object.
Source
Thrown at packages/data-table-mysql/src/lib/sql-compiler.ts:113
values: context.values,
}
}
if (operation.kind === 'delete') {
return {
text:
'delete from ' +
quotePath(getTableName(operation.table)) +
compileWhereClause(operation.where, context),
values: context.values,
}
}
if (operation.kind === 'upsert') {
return compileUpsertOperation(operation, context)
}
throw new Error('Unsupported operation kind')
}
function compileInsertOperation(
table: OperationTable,
values: Record<string, unknown>,
context: CompileContext,
): SqlStatement {
let columns = Object.keys(values)
if (columns.length === 0) {
return {
text: 'insert into ' + quotePath(getTableName(table)) + ' () values ()',
values: context.values,
}
}
return {
text:View on GitHub (pinned to 9696913134)
Solutions
- Use the official operation builder functions for the MySQL driver instead of hand-built objects
- Align versions of the data-table core package and the MySQL backend package
- Check the operation.kind against the MySQL compiler's supported kinds before compiling
Example fix
// before
const op = { kind: 'merge', table: 'users', values } // unsupported kind
await driver.execute(compile(op))
// after
const op = upsertOp('users', values, { update: values })
await driver.execute(compile(op)) Defensive patterns
Strategy: type-guard
Validate before calling
const supported = new Set(['insert', 'update', 'delete', 'upsert'])
if (!supported.has(op.kind)) throw new Error(`unsupported kind ${op.kind} for MySQL`) Type guard
type MysqlOperationKind = 'insert' | 'update' | 'delete' | 'upsert'
function isMysqlOperation(op: { kind: string }): op is { kind: MysqlOperationKind } {
return ['insert', 'update', 'delete', 'upsert'].includes(op.kind)
} Try / catch
try { const sql = compileMysqlOperation(op, ctx) } catch (e) { if (e instanceof Error && e.message === 'Unsupported operation kind') { /* rebuild op with supported builder */ } throw e } Prevention
- Always build operations via the driver's builder APIs
- Keep data-table core and MySQL backend package versions in sync
When it happens
Trigger: Passing a hand-constructed operation like { kind: 'merge', ... } or { kind: 'bulkInsert' } to driver compile/execute APIs; mixing operation builders from a different data-table backend (postgres) with the MySQL driver; typos in kind strings.
Common situations: Version mismatch where a newer @remix-run/data-table core emits a kind the installed MySQL compiler doesn't know; custom operation construction instead of using builder APIs; copying operation examples from another backend's docs.
Related errors
- upsert requires at least one value
- Unknown transaction token: + token.id
- MySQL migration lock is already held by this database
- MySQL database + method + () requires config-based construc
- MySQL database cannot + method + while transactions are op
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/1cde3929808213ee.
Report an issue: GitHub.