TanStack/table · error
coreColumnsFeature require an id when using an accessorFn
Error message
coreColumnsFeature require an id when using an accessorFn
What it means
constructColumn in packages/table-core derives a column id from accessorKey or header string. When a column uses accessorFn (a function accessor) there is no key to infer an id from, so if no explicit id is given the library throws this dev-mode error rather than generating a duplicate-prone implicit id.
Source
Thrown at packages/table-core/src/core/columns/constructColumn.ts:94
result = result?.[key]
if (process.env.NODE_ENV === 'development' && result === undefined) {
console.warn(
`"${key}" in deeply nested key "${accessorKey}" returned undefined.`,
)
}
}
return result as TValue
}
} else {
accessorFn = (originalRow: TData) =>
(originalRow as any)[resolvedColumnDef.accessorKey]
}
}
if (!id) {
if (process.env.NODE_ENV === 'development') {
throw new Error(
resolvedColumnDef.accessorFn
? `coreColumnsFeature require an id when using an accessorFn`
: `coreColumnsFeature require an id when using a non-string header`,
)
}
throw new Error()
}
// Create column with shared prototype for memory efficiency
const columnPrototype = getColumnPrototype(table)
const column = Object.create(columnPrototype) as Column_CoreProperties<
TFeatures,
TData,
TValue
>
// Only assign instance-specific properties
column.accessorFn = accessorFnView on GitHub (pinned to d01c01bedb)
Solutions
- Add an explicit id to the column definition alongside accessorFn.
- If the column also has a string header usable as id, set id to the same stable string used elsewhere (row.getCellValue, grouping keys).
- Verify all generated/dynamic column defs always include id when accessorFn is present.
Example fix
// before
{ accessorFn: (row) => row.user.name, header: 'User' }
// after
{ id: 'user.name', accessorFn: (row) => row.user.name, header: 'User' } Defensive patterns
Strategy: validation
Validate before calling
function assertColumnHasId(def) {
if (!def.id && def.accessorFn) {
throw new Error('Column with accessorFn requires an explicit id: ' + (def.header ?? def))
}
}
columns.forEach(assertColumnHasId) // before createTable/columns feature init Type guard
function hasRequiredId(def: ColumnDef<any>): def is ColumnDef<any> & { id: string } {
return typeof def.id === 'string' && def.id.length > 0
} Try / catch
try {
const column = constructColumn(id, originalColumnDef, resolvedColumnDef, table)
} catch (e) {
if ((e as Error).message.includes('require an id')) {
console.error('Column definition missing id:', originalColumnDef)
} else throw e
} Prevention
- Always set id when using accessorFn
- Validate column defs at build time with a schema/lint rule
- Keep ids stable and unique across refactors
When it happens
Trigger: Passing a columnDef with accessorFn: (row) => ... but no id property, in development (NODE_ENV === 'development').
Common situations: Defining data-only columns with function accessors in an array of columnDefs; renaming accessorKey to accessorFn while removing id; dynamically built column configs.
Related errors
- coreColumnsFeature require an id when using a non-string hea
- "${key}" in deeply nested key "${accessorKey}" returned unde
- [Table] Column with id '${columnId}' does not exist.
- filterFn '${filterFnName}' (auto) for column '${column.id}'
- filterFn '${String(column.columnDef.filterFn)}' for column '
AI-assisted analysis of TanStack/table@d01c01bedb (2026-08-28).
Data as JSON: /api/errors/b68025e142650aac.
Report an issue: GitHub.