payloadcms/payload · error · Error

Field "${field.name}" of type "${field.type}" has an empty r

Error message

Field "${field.name}" of type "${field.type}" has an empty relationTo array. At least one collection must be specified.

What it means

A `relationship` or `upload` field has `relationTo` set to an empty array (`relationTo: []`). relationship/upload fields must point to at least one target collection slug; an empty array is meaningless and breaks schema generation and the admin select UI.

Source

Thrown at packages/payload/src/fields/config/sanitize.ts:254

  }

  // Join field sanitization
  if (field.type === 'join') {
    sanitizeJoinField({
      config,
      field,
      joinPath,
      joins,
      orderableJoins,
      parentIsLocalized,
      polymorphicJoins,
    })
  }

  // Relationship/upload validation
  if (field.type === 'relationship' || field.type === 'upload') {
    if (Array.isArray(field.relationTo) && field.relationTo.length === 0) {
      throw new Error(
        `Field "${field.name}" of type "${field.type}" has an empty relationTo array. At least one collection must be specified.`,
      )
    }

    if (validRelationships) {
      const relationships = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]

      relationships.forEach((relationship: string) => {
        if (!validRelationships.includes(relationship)) {
          throw new InvalidFieldRelationship(field, relationship)
        }
      })
    }
  }

  // Upload isSortable default
  if (field.type === 'upload') {
    if (!field.admin || !('isSortable' in field.admin)) {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Provide at least one valid collection slug in `relationTo`.
  2. If the field should not exist when the list is empty, conditionally omit the whole field from the fields array.
  3. For upload fields, set `relationTo` to a single upload-enabled collection slug.

Example fix

// before
{ type: 'relationship', name: 'related', relationTo: [] }
// after
{ type: 'relationship', name: 'related', relationTo: ['posts'] }
Defensive patterns

Strategy: validation

Validate before calling

function findEmptyRelationTo(fields) {
  const bad = []
  for (const f of fields) {
    if ((f?.type === 'relationship' || f?.type === 'upload') && Array.isArray(f?.relationTo) && f.relationTo.length === 0) {
      bad.push(f.name)
    }
    if (Array.isArray(f?.fields)) bad.push(...findEmptyRelationTo(f.fields))
  }
  return bad
}

Type guard

function relationToIsNonEmpty(f: any): boolean {
  if (f?.type !== 'relationship' && f?.type !== 'upload') return true
  if (Array.isArray(f.relationTo)) return f.relationTo.length > 0
  return typeof f.relationTo === 'string' && f.relationTo.length > 0
}

Try / catch

try {
  await payload.init({ config })
} catch (err) {
  if (/empty relationTo/i.test(err?.message ?? '')) console.error('relationship/upload field with empty relationTo')
  throw err
}

Prevention

When it happens

Trigger: `{ type: 'relationship', name: 'x', relationTo: [] }` or an upload field with empty relationTo; dynamically building `relationTo` from a filtered list that ends up empty.

Common situations: Computing `relationTo` from an env/config-driven list that resolves to nothing in some environment; partial refactor leaving `relationTo: []` as a placeholder; conditional spread that omits all entries.

Related errors


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