remix-run/remix · error · DataTableValidationError
Unknown column "' + key + '" for table "' + tableName + '"
Error message
Unknown column "' + key + '" for table "' + tableName + '"
What it means
After confirming the written value is an object, the library checks each key against the table's declared columns via getTableColumns. A key that is not a column of that table produces a DataTableValidationError naming the unknown column — this catches typos and renamed columns before they reach SQL, and also prevents accidental injection of stray properties.
Source
Thrown at packages/data-table/src/lib/database/write-lifecycle.ts:382
{
metadata: {
table: tableName,
operation,
...(source ? { source } : {}),
},
},
)
}
let output: Record<string, unknown> = {}
for (let key in value) {
if (!Object.prototype.hasOwnProperty.call(value, key)) {
continue
}
if (!Object.prototype.hasOwnProperty.call(columns, key)) {
throw new DataTableValidationError(
'Unknown column "' + key + '" for table "' + tableName + '"',
[],
{
metadata: {
table: tableName,
column: key,
operation,
...(source ? { source } : {}),
},
},
)
}
output[key] = (value as Record<string, unknown>)[key]
}
return output
}View on GitHub (pinned to 9696913134)
Solutions
- Fix the property name to match a declared column exactly
- Whitelist/pick only known columns before writing: pick(values, ...columnNames)
- If the field should exist, add the column to defineTable first
Example fix
// before
await userTable.create({ values: req.json() }) // contains extra fields
// after
let body = req.json()
await userTable.create({
values: { name: body.name, email: body.email },
}) Defensive patterns
Strategy: validation
Validate before calling
let allowed = new Set(Object.keys(getTableColumns(table)))
let safe = Object.fromEntries(Object.entries(values).filter(([k]) => allowed.has(k)))
await table.create({ values: safe }) Type guard
function hasOnlyKnownColumns(values: Record<string, unknown>, columns: Record<string, unknown>): boolean {
return Object.keys(values).every((key) => Object.prototype.hasOwnProperty.call(columns, key))
} Try / catch
try {
await table.create({ values })
} catch (error) {
if (error instanceof DataTableValidationError && /Unknown column/.test(error.message)) {
return new Response(error.message, { status: 400 })
} else throw error
} Prevention
- Whitelist columns derived from the table schema before writing untrusted data
- Keep API payload types in sync with table definitions
- Run migrations and update code together when renaming columns
When it happens
Trigger: create({ values: { emial: 'a@b.com' } }) with the column spelled email; sending request JSON that includes extra fields (timestamps, ids, nested objects) not declared on the table; referencing a column after renaming it in the schema.
Common situations: Unvalidated request bodies forwarded straight into write APIs; schema drift between an API client and the table definition; spreading objects that carry extra metadata (e.g. joined rows) into an update.
Related errors
- upsert requires at least one value
- insertMany() requires at least one explicit value across the
- update() requires at least one change
- Invalid afterRead callback result for table "' + tableName +
- Invalid beforeDelete callback result for table "' + context.
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/3bce50e698329ada.
Report an issue: GitHub.