payloadcms/payload · error · APIError

${e.message}

Error message

${e.message}

What it means

Thrown during the one-time orderable migration: when `orderable` is first enabled on a collection that already has documents, Payload back-fills the ordering key for each existing doc by calling `payload.update` inside a transaction. If any per-doc update throws an `Error`, the transaction is killed and the message is re-thrown as an `APIError` with HTTP 500.

Source

Thrown at packages/payload/src/config/orderable/index.ts:232

      // We cannot update all documents in a single operation with `payload.update`,
      // because they would all end up with the same order key (`a0`).
      try {
        for (const doc of docs) {
          await req.payload.update({
            id: doc.id,
            collection: collection.slug,
            data: {
              // no data needed since the order hooks will handle this
            },
            depth: 0,
            req,
          })
          await commitTransaction(req)
        }
      } catch (e) {
        await killTransaction(req)
        if (e instanceof Error) {
          throw new APIError(e.message, httpStatus.INTERNAL_SERVER_ERROR)
        }
      }

      return new Response(JSON.stringify({ message: 'initial migration', success: true }), {
        headers: { 'Content-Type': 'application/json' },
        status: 200,
      })
    }

    if (
      typeof target !== 'object' ||
      typeof target.id === 'undefined' ||
      typeof target.key !== 'string'
    ) {
      return new Response(JSON.stringify({ error: 'target must be an object with id' }), {
        headers: { 'Content-Type': 'application/json' },
        status: 400,
      })

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Inspect the wrapped `e.message` (surfaced via the APIError) to find the underlying field/hook error.
  2. Fix or clean the offending documents so they pass validation, then retry the reorder request.
  3. Temporarily disable offending hooks or loosen validation, run the migration, then restore them.

Example fix

// before: enabling orderable on a collection with invalid legacy docs
collections: [{ slug: 'items', orderable: true, fields: [{ name: 'title', required: true }] }]
// after: backfill missing titles first, then enable orderable
await payload.update({ collection: 'items', where: { title: { exists: false } }, data: { title: 'Untitled' } })
Defensive patterns

Strategy: try-catch

Validate before calling

// Before enabling orderable, ensure existing docs pass current validation
const { docs } = await payload.find({ collection: 'items', limit: 0, depth: 0, req })
for (const d of docs) {
  await payload.update({ collection: 'items', id: d.id, data: {}, req }).catch((e) => {
    throw new Error(`Doc ${d.id} would fail orderable migration: ${e.message}`)
  })
}

Try / catch

try {
  await fetch('/api/items/reorder', { method: 'POST', body: JSON.stringify({ target: { key: null } }) })
} catch (err) {
  if (err instanceof APIError && err.status === 500) {
    // initial orderable migration failed — fix the offending docs, then retry
  }
  throw err
}

Prevention

When it happens

Trigger: Enabling `orderable: true` on a collection that already contains rows, where one of those rows fails validation during the back-fill (e.g. a required field now missing, a beforeChange hook rejecting, a unique constraint hit).

Common situations: Adding orderable to a long-lived collection with legacy data that violates current field constraints; a `beforeChange`/`beforeValidate` hook that throws on legacy docs; concurrent edits during the migration.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/d6e3f5c348b63f7f. Report an issue: GitHub.