remix-run/remix · error · Error
Invalid column "{columnName}" for table "{tableName}". Expec
Error message
Invalid column "{columnName}" for table "{tableName}". Expected a column(...) builder What it means
This error is thrown by resolveTableColumns when a table's column definition object contains a value that is not a ColumnBuilder instance. Every entry in the columns object passed to defineTable/createTable must be created with the column(...) builder so the library can read its type, options, and defaults.
Source
Thrown at packages/data-table/src/lib/table.ts:803
}),
}) as ColumnReference<tableName, columnName>
}
function resolveTableColumns<columns extends TableColumnsDefinition>(
tableName: string,
columns: columns,
): { [column in keyof columns & string]: ColumnDefinition } {
let columnDefinitions: Record<string, ColumnDefinition> = {}
for (let columnName in columns) {
if (!Object.prototype.hasOwnProperty.call(columns, columnName)) {
continue
}
let column = columns[columnName]
if (!(column instanceof ColumnBuilder)) {
throw new Error(
'Invalid column "' +
columnName +
'" for table "' +
tableName +
'". Expected a column(...) builder',
)
}
columnDefinitions[columnName] = column.build()
}
return Object.freeze(columnDefinitions) as {
[column in keyof columns & string]: ColumnDefinition
}
}
/**
* Defines a one-to-many relation from `source` to `target`.View on GitHub (pinned to 9696913134)
Solutions
- Ensure every columns entry is created with the library's column(...) builder
- Check for typos like passing column types (e.g. 'string') instead of column.string()
- Remove any spread of non-builder objects from the columns definition
Example fix
// before
const posts = createTable('posts', {
title: 'string',
})
// after
import { column, createTable } from '...'
const posts = createTable('posts', {
title: column.string(),
}) Defensive patterns
Strategy: validation
Validate before calling
for (const [name, def] of Object.entries(columns)) {
if (!(def instanceof ColumnBuilder)) throw new TypeError(`column ${name} is not a builder`)
} Type guard
const isColumnBuilder = (v: unknown): v is ColumnBuilder => v instanceof ColumnBuilder
Prevention
- Always construct columns with the library's column(...) builder
- Type the columns argument as Record<string, ColumnBuilder> so TS rejects plain values
When it happens
Trigger: Passing a plain value, class instance, or imported non-builder (e.g. columns: { id: 1 } or { createdAt: SomeORM.column }) inside the table's columns definition; also wrapping columns in an extra layer or passing a serialized/parsed definition.
Common situations: Copy-pasting schema code from another ORM, forgetting to call column(), spreading plain objects into the columns definition, or a refactor that renamed the column import.
Related errors
- upsert requires at least one value
- onDelete() requires references() to be set first
- onUpdate() requires references() to be set first
- insertMany() requires at least one explicit value across the
- update() requires at least one change
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/34e9f664c5408aa1.
Report an issue: GitHub.