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
- Inspect the wrapped `e.message` (surfaced via the APIError) to find the underlying field/hook error.
- Fix or clean the offending documents so they pass validation, then retry the reorder request.
- 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
- Backfill/validate legacy docs before enabling `orderable`.
- Keep `beforeChange` hooks tolerant of legacy data during the migration window.
- Run the first reorder against a staging copy of the data.
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
- Either collectionSlug or globalSlug must be provided
- Cannot provide both collectionSlug and globalSlug
- Localization is not enabled in payload config
- ${collectionSlug ? 'Collection' : 'Global'} not found: ${col
- Migration aborted: version._status field not found or has un
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/d6e3f5c348b63f7f.
Report an issue: GitHub.