remix-run/remix · error · DataTableQueryError

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

Error message

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

What it means

With returnRow: true and relations to load (options.with), create() first inserts, then re-fetches the row with findOne to hydrate relations. If that findOne returns nothing — the row vanished between insert and select — this error is thrown. Typically caused by triggers, default scopes, or a where built from a returned row that doesn't match stored data.

Source

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

      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')
      }

      return loaded
    }

    let insertResult = await query.insert(values, { touch })
    let where = resolveCreateRowWhere(table, values, toWriteResult(insertResult).insertId)
    let loaded = await this.findOne(table, {
      where,
      with: options.with,
    })

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

    return loaded
  }

View on GitHub (pinned to 9696913134)

Solutions

  1. Verify no trigger/policy rewrites or hides the inserted row; test the same insert+select manually.
  2. Omit `with` (fetch relations in a second explicit findOne you control) to isolate whether hydration or insert is at fault.
  3. If it persists, drop returnRow and load the row manually with an explicit where you know matches stored data.

Example fix

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

// after
let { id } = await db.create(users, values)
let row = await db.findOne(users, (q) => q.where(eq(users.id, id)).with({ posts: true }))
Defensive patterns

Strategy: fallback

Validate before calling

// Prefer explicit keys when hydrating relations after create
let result = await db.create(table, values)
let row = await db.findOne(table, primaryKeyWhere(table, result))

Try / catch

try {
  return await db.create(t, v, { returnRow: true, with })
} catch (error) {
  if (error instanceof DataTableQueryError && /failed to load/.test(error.message)) {
    // fall back to a manual find with a known-good where
  }
}

Prevention

When it happens

Trigger: db.create(table, values, { returnRow: true, with: {...} }) where the subsequent findOne (using a primary-key where from the inserted row) finds no row: BEFORE INSERT triggers rewriting keys, RLS policies, or generated/rewritten primary keys the driver doesn't round-trip.

Common situations: SQLite triggers (e.g. rowid tables with conflicting INTEGER PRIMARY KEY aliasing) changing the stored row; databases where the driver fails to obtain the real key; row-level security filtering the re-select.

Related errors


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