remix-run/remix · error · DataTableQueryError
update() failed to find row for table "' + getTableName(tabl
Error message
update() failed to find row for table "' + getTableName(table) + '"
What it means
update() with returning support executes the UPDATE with returning: '*' and takes rows[0] as the updated row. If the driver reports zero affected rows, this error is thrown — meaning the WHERE clause matched no row, so the update was a no-op.
Source
Thrown at packages/data-table/src/lib/database.ts:773
table extends AnyTable,
relations extends RelationMapForSourceName<TableName<table>> = {},
>(
table: table,
value: PrimaryKeyInput<table>,
changes: Partial<TableRow<table>>,
options?: UpdateOptions<table, relations>,
): Promise<TableRowWith<table, LoadedRelationMap<relations>>> {
let where = getPrimaryKeyWhere(table, value)
if (this.capabilities.returning) {
let updateResult = (await this.query(asQueryTableInput(table)).where(where).update(changes, {
touch: options?.touch,
returning: '*',
})) as { rows: TableRow<table>[] }
let updatedRow = updateResult.rows[0]
if (!updatedRow) {
throw new DataTableQueryError(
'update() failed to find row for table "' + getTableName(table) + '"',
)
}
if (!options?.with) {
return updatedRow as TableRowWith<table, LoadedRelationMap<relations>>
}
let loaded = await this.findOne(table, {
where: getPrimaryKeyWhereFromRow(table, updatedRow),
with: options.with,
})
if (!loaded) {
throw new DataTableQueryError(
'update() failed to find row for table "' + getTableName(table) + '"',
)
}View on GitHub (pinned to 9696913134)
Solutions
- Check existence first (db.find) or design the flow to tolerate a missing row instead of treating no-op updates as exceptions.
- Verify the id/where you pass actually identifies an existing row (log it, inspect the table).
- For upsert semantics, use the upsert API instead of update.
Example fix
// before
let row = await db.update(users, params.id, values)
// after
let row = await db.find(users, params.id)
if (!row) throw new Response('Not Found', { status: 404 })
row = await db.update(users, params.id, values) Defensive patterns
Strategy: validation
Validate before calling
let existing = await db.find(users, params.id)
if (!existing) throw new Response('Not Found', { status: 404 })
let row = await db.update(users, params.id, values) Try / catch
try {
await db.update(t, id, values)
} catch (error) {
if (error instanceof DataTableQueryError && /failed to find row/.test(error.message)) {
throw new Response('Not Found', { status: 404 })
}
} Prevention
- Treat update-misses as 404s in route handlers.
- Refresh client state before edits; prefer upsert for create-or-update flows.
When it happens
Trigger: db.update(table, idOrWhere, values) where the target row does not exist (already deleted, wrong id, or where matches nothing); concurrent deletion between a read and the update.
Common situations: Optimistic UI updating a record another request deleted; stale ids from previous page state; where clauses built from optional filters that end up matching nothing.
Related errors
- MySQL migration lock could not be acquired
- update() requires at least one change
- Unknown transaction token: + token.id
- MySQL migration lock is already held by this database
- MySQL database + method + () requires config-based construc
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/0945a64e7e1108c0.
Report an issue: GitHub.