remix-run/remix · error · DataTableQueryError

create({ returnRow: true }) failed to return an inserted row

Error message

create({ returnRow: true }) failed to return an inserted row

What it means

When create() is called with returnRow: true and the database supports RETURNING, it executes the insert with returning: '*' and expects a row back. If the driver returns no row (result.row is null/undefined), this error is thrown, indicating the insert succeeded as a statement but the driver/compiler failed to return the inserted data — a driver contract violation rather than a caller mistake.

Source

Thrown at packages/data-table/src/lib/database.ts:580

    options?: CreateResultOptions | CreateRowOptions<table, relations>,
  ): Promise<WriteResult | TableRowWith<table, LoadedRelationMap<relations>>> {
    let touch = options?.touch
    let query: QueryForTable<table> = this.query(asQueryTableInput(table))

    if (options?.returnRow !== true) {
      let result = await query.insert(values, { touch })
      return toWriteResult(result)
    }

    if (this.capabilities.returning) {
      let result = (await query.insert(values, {
        returning: '*',
        touch,
      })) as { row: TableRow<table> | null }
      let row = result.row

      if (!row) {
        throw new DataTableQueryError(
          'create({ returnRow: true }) failed to return an inserted row',
        )
      }

      if (!options.with) {
        return row as TableRowWith<table, LoadedRelationMap<relations>>
      }

      let where = getPrimaryKeyWhereFromRow(table, row)
      let loaded = await this.findOne(table, {
        where,
        with: options.with,
      })

      if (!loaded) {
        throw new DataTableQueryError('create({ returnRow: true }) failed to load inserted row')
      }

View on GitHub (pinned to 9696913134)

Solutions

  1. If you maintain the driver, ensure inserts with returning: '*' resolve with { row } populated from the RETURNING result.
  2. If using a built-in driver, update data-table and driver packages to matching versions — this indicates a driver bug.
  3. As a workaround, drop returnRow and re-fetch the row yourself via findOne using the primary key.

Example fix

// before
let row = await db.create(users, values, { returnRow: true })

// after
let result = await db.create(users, values)
let row = await db.findOne(users, eq(users.id, result.primaryKey))
Defensive patterns

Strategy: fallback

Validate before calling

if (db.capabilities.returning) {
  row = await db.create(table, values, { returnRow: true })
} else {
  await db.create(table, values)
  row = await db.findOne(table, where)
}

Try / catch

try {
  return await db.create(t, v, { returnRow: true })
} catch (error) {
  if (error instanceof DataTableQueryError && /failed to return/.test(error.message)) {
    return await db.findOne(t, where) // manual fallback
  }
  throw error
}

Prevention

When it happens

Trigger: db.create(table, values, { returnRow: true }) on a database advertising capabilities.returning where the RETURNING clause is dropped or the driver mis-parses the returned row; custom drivers that resolve inserts without echoing rows.

Common situations: Writing/testing a custom driver that forgets to map RETURNING results; SQLite wrappers where lastInsertRowid is used but the row fetch fails; version skew between driver and core.

Related errors


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