remix-run/remix · error · DataTableQueryError
Relation "' + relationName + '" is not defined for source ta
Error message
Relation "' + relationName + '" is not defined for source table "' + getTableName(sourceTable) + '"
What it means
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.
Source
Thrown at packages/data-table/src/lib/database/relations.ts:35
any,
{ binding: 'unbound'; mode: 'all' }
>
export async function loadRelationsForRows(
database: QueryExecutionContext,
sourceTable: AnyTable,
rows: Record<string, unknown>[],
relationMap: Record<string, AnyRelation>,
): Promise<Record<string, unknown>[]> {
let output = rows.map((row) => ({ ...row }))
let relationNames = Object.keys(relationMap)
for (let relationName of relationNames) {
let relation = relationMap[relationName]
if (relation.sourceTable !== sourceTable) {
throw new DataTableQueryError(
'Relation "' +
relationName +
'" is not defined for source table "' +
getTableName(sourceTable) +
'"',
)
}
let values = await resolveRelationValues(database, output, relation)
let index = 0
while (index < output.length) {
output[index][relationName] = values[index]
index += 1
}
}
return outputView on GitHub (pinned to 9696913134)
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
Example fix
// before
let postTable = defineTable({
relations: () => ({
author: userTable.hasMany(/* oops: sourced from userTable's posts */),
}),
})
// after
let postTable = defineTable({
relations: () => ({
author: postTable.belongsTo(() => userTable, { foreignKey: 'authorId' }),
}),
}) Defensive patterns
Strategy: validation
Validate before calling
for (let [name, relation] of Object.entries(relationMap)) {
if (relation.sourceTable !== table) {
throw new Error(`Relation ${name} declared on wrong table`)
}
} Type guard
function isRelationForTable(relation: AnyRelation, table: unknown): boolean {
return relation.sourceTable === table
} Try / catch
try {
rows = await loadRowsWithRelations(state)
} catch (error) {
if (error instanceof DataTableQueryError && /is not defined for source table/.test(error.message)) {
// load without relations and log the misconfigured relation
} else throw error
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- create({ returnRow: true }) failed to load inserted row
- hasManyThrough relation is missing through metadata
- hasManyThrough expects a through relation whose source table
- Relation key mismatch between "{sourceTableName}" ({sourceKe
- Unknown transaction token: + token.id
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/f4e1f509a1ea476f.
Report an issue: GitHub.