{"record":{"id":"f4e1f509a1ea476f","repo":"remix-run/remix","slug":"relation-relationname-is-not-defined-for","errorCode":null,"errorMessage":"Relation \"' + relationName + '\" is not defined for source table \"' + getTableName(sourceTable) + '\"","messagePattern":"Relation \"' \\+ relationName \\+ '\" is not defined for source table \"' \\+ getTableName\\(sourceTable\\) \\+ '\"","errorType":"exception","errorClass":"DataTableQueryError","httpStatus":null,"severity":"error","filePath":"packages/data-table/src/lib/database/relations.ts","lineNumber":35,"sourceCode":"  any,\n  { binding: 'unbound'; mode: 'all' }\n>\n\nexport async function loadRelationsForRows(\n  database: QueryExecutionContext,\n  sourceTable: AnyTable,\n  rows: Record<string, unknown>[],\n  relationMap: Record<string, AnyRelation>,\n): Promise<Record<string, unknown>[]> {\n  let output = rows.map((row) => ({ ...row }))\n\n  let relationNames = Object.keys(relationMap)\n\n  for (let relationName of relationNames) {\n    let relation = relationMap[relationName]\n\n    if (relation.sourceTable !== sourceTable) {\n      throw new DataTableQueryError(\n        'Relation \"' +\n          relationName +\n          '\" is not defined for source table \"' +\n          getTableName(sourceTable) +\n          '\"',\n      )\n    }\n\n    let values = await resolveRelationValues(database, output, relation)\n    let index = 0\n\n    while (index < output.length) {\n      output[index][relationName] = values[index]\n      index += 1\n    }\n  }\n\n  return output","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/data-table/src/lib/database/relations.ts#L17-L53","documentation":"During relation loading, the library walks the relation map for the source table and verifies each relation was actually declared on that table. If a relation object's sourceTable differs from the table rows being loaded from, the relation cannot be applied and a DataTableQueryError names the mismatched relation and table. This almost always indicates a relations definition attached to the wrong table.","triggerScenarios":"Defining relations({ items: itemTable.hasMany(...) }) on table A but the relation objects are sourced from table B; reusing a relation object across tables; spreading another table's relation map into this table's definition.","commonSituations":"Copy-pasting relation definitions between tables; refactor renaming/moving tables while the relation objects still reference the old source; composing relation maps dynamically and mixing entries from multiple tables.","solutions":["Define each relation on the table it belongs to: use the matching table's hasMany/hasOne/belongsTo builder so sourceTable matches","Don't share or spread relation objects between different tables' relation maps","After refactors, audit every entry in relations() to confirm it is built from the table it is declared on"],"exampleFix":"// before\nlet postTable = defineTable({\n  relations: () => ({\n    author: userTable.hasMany(/* oops: sourced from userTable's posts */),\n  }),\n})\n\n// after\nlet postTable = defineTable({\n  relations: () => ({\n    author: postTable.belongsTo(() => userTable, { foreignKey: 'authorId' }),\n  }),\n})","handlingStrategy":"validation","validationCode":"for (let [name, relation] of Object.entries(relationMap)) {\n  if (relation.sourceTable !== table) {\n    throw new Error(`Relation ${name} declared on wrong table`)\n  }\n}","typeGuard":"function isRelationForTable(relation: AnyRelation, table: unknown): boolean {\n  return relation.sourceTable === table\n}","tryCatchPattern":"try {\n  rows = await loadRowsWithRelations(state)\n} catch (error) {\n  if (error instanceof DataTableQueryError && /is not defined for source table/.test(error.message)) {\n    // load without relations and log the misconfigured relation\n  } else throw error\n}","preventionTips":["Always declare relations inside the owning table's defineTable().relations callback","Never spread another table's relation map into this table's definition","Add a startup smoke test that loads one row with relations from every table"],"tags":["data-table","relations","schema-definition"],"backgroundTag":"relation-defined-on-wrong-table","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}