{"record":{"id":"8622f44d7879f471","repo":"remix-run/remix","slug":"composite-primary-keys-require-an-object-value","errorCode":null,"errorMessage":"Composite primary keys require an object value","messagePattern":"Composite primary keys require an object value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/data-table/src/lib/table.ts","lineNumber":1026,"sourceCode":"/**\n * Normalizes a primary-key input into an object keyed by primary-key columns.\n * @param table Source table.\n * @param value Primary-key input value.\n * @returns Primary-key object.\n */\nexport function getPrimaryKeyObject<table extends AnyTable>(\n  table: table,\n  value: PrimaryKeyInput<table>,\n): Partial<TableRow<table>> {\n  let keys = getTablePrimaryKey(table)\n\n  if (keys.length === 1 && (typeof value !== 'object' || value === null || Array.isArray(value))) {\n    let key = keys[0] as keyof TableRow<table>\n    return { [key]: value } as Partial<TableRow<table>>\n  }\n\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    throw new Error('Composite primary keys require an object value')\n  }\n\n  let objectValue = value as Record<string, unknown>\n  let output: Partial<TableRow<table>> = {}\n\n  for (let key of keys) {\n    if (!(key in objectValue)) {\n      throw new Error(\n        'Missing key \"' + key + '\" for primary key lookup on \"' + getTableName(table) + '\"',\n      )\n    }\n\n    ;(output as Record<string, unknown>)[key] = objectValue[key]\n  }\n\n  return output\n}\n","sourceCodeStart":1008,"sourceCodeEnd":1044,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table/src/lib/table.ts#L1008-L1044","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet row = await db.members.find('tenant-1')\n// after\nlet row = await db.members.find({ tenantId: 'tenant-1', memberId: 'm-9' })","handlingStrategy":"type-guard","validationCode":"if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new TypeError('expected key object')","typeGuard":"const isKeyObject = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v)","tryCatchPattern":null,"preventionTips":["For composite keys, always pass an object keyed by primary key columns","Grep lookup call sites after changing primaryKey"],"tags":["data-table","primary-key","lookup"],"backgroundTag":"composite-primary-key-lookup","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}