remix-run/remix · error · Error
Composite primary keys require an object value
Error message
Composite primary keys require an object value
What it means
When a table has a composite primary key, row lookups require the key value to be a plain object mapping each key column to its value. This error is thrown when the provided value is a primitive, null, or an array while multiple key columns are expected.
Source
Thrown at packages/data-table/src/lib/table.ts:1026
/**
* Normalizes a primary-key input into an object keyed by primary-key columns.
* @param table Source table.
* @param value Primary-key input value.
* @returns Primary-key object.
*/
export function getPrimaryKeyObject<table extends AnyTable>(
table: table,
value: PrimaryKeyInput<table>,
): Partial<TableRow<table>> {
let keys = getTablePrimaryKey(table)
if (keys.length === 1 && (typeof value !== 'object' || value === null || Array.isArray(value))) {
let key = keys[0] as keyof TableRow<table>
return { [key]: value } as Partial<TableRow<table>>
}
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
throw new Error('Composite primary keys require an object value')
}
let objectValue = value as Record<string, unknown>
let output: Partial<TableRow<table>> = {}
for (let key of keys) {
if (!(key in objectValue)) {
throw new Error(
'Missing key "' + key + '" for primary key lookup on "' + getTableName(table) + '"',
)
}
;(output as Record<string, unknown>)[key] = objectValue[key]
}
return output
}
View on GitHub (pinned to 9696913134)
Solutions
- Pass an object with every primary key column: { tenantId, postId }
- If the table really should have a single key, fix the table definition's primaryKey
- Search call sites for scalar lookups after changing a primaryKey to composite
Example fix
// before
let row = await db.members.find('tenant-1')
// after
let row = await db.members.find({ tenantId: 'tenant-1', memberId: 'm-9' }) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new TypeError('expected key object') Type guard
const isKeyObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v)
Prevention
- For composite keys, always pass an object keyed by primary key columns
- Grep lookup call sites after changing primaryKey
When it happens
Trigger: Calling a find/lookup API like db.posts.find('a') on a table whose primaryKey is ['tenantId','postId'], or passing an array of values instead of an object.
Common situations: Migrating a single-column id table to a composite key but keeping old scalar lookup call sites; forgetting the composite-key convention after reading docs written for id tables.
Related errors
- Missing key "{key}" for primary key lookup on "{getTableName
- create({ returnRow: true }) requires primary key values for
- Table "{tableName}" must include an "id" column or an explic
- Table "{tableName}" primaryKey must contain at least one col
- Table "{tableName}" primaryKey column "{key}" does not exist
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/8622f44d7879f471.
Report an issue: GitHub.