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 output

View on GitHub (pinned to 9696913134)

Solutions

  1. Define each relation on the table it belongs to: use the matching table's hasMany/hasOne/belongsTo builder so sourceTable matches
  2. Don't share or spread relation objects between different tables' relation maps
  3. 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

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


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/f4e1f509a1ea476f. Report an issue: GitHub.