payloadcms/payload · error · APIError

Relationship field was not found

Error message

Relationship field was not found

What it means

For a join-type field in a nested query, buildSearchParam resolves the join's target relationship field via getFieldByPath on the collection's flattenedFields using field.on. If no field exists at that path, it throws APIError. The join field's `on` must point to an existing relationship field on the same collection.

Source

Thrown at packages/db-mongodb/src/queries/buildSearchParams.ts:171

              },
            },
          })

          const field = paths[0].field

          const select: Record<string, boolean> = {
            _id: true,
          }

          let joinPath: null | string = null

          if (field.type === 'join') {
            const relationshipField = getFieldByPath({
              fields: collectionConfig.flattenedFields,
              path: field.on,
            })
            if (!relationshipField) {
              throw new APIError('Relationship field was not found')
            }

            let path = relationshipField.localizedPath
            if (relationshipField.pathHasLocalized && payload.config.localization) {
              path = path.replace('<locale>', locale || payload.config.localization.defaultLocale)
            }
            select[path] = true

            joinPath = path
          }

          if (joinPath) {
            select[joinPath] = true
          }

          const result = await SubModel.find(subQuery).lean().select(select)

          const $in: unknown[] = []

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Open the collection config and confirm the join field's `on` matches an existing relationship/upload field name/path.
  2. If the relationship field was renamed, update the join's `on` to the new name.
  3. Ensure `on` points to a relationship-type field, not a group/array/blocks field.
  4. Re-run payload's config validation to surface the misconfiguration at boot.

Example fix

// before
{
  slug: 'posts',
  fields: [
    { name: 'author', type: 'relationship', relationTo: 'users' },
    { name: 'comments', type: 'join', on: 'writer' }, // 'writer' does not exist
  ],
}

// after
{
  slug: 'posts',
  fields: [
    { name: 'author', type: 'relationship', relationTo: 'users' },
    { name: 'comments', type: 'join', on: 'author' },
  ],
}
Defensive patterns

Strategy: validation

Validate before calling

import { getFieldByPath } from 'payload'

function assertJoinOnExists(collectionConfig: { flattenedFields: any[] }, joinField: { type: 'join'; on: string }) {
  if (joinField.type !== 'join') return
  const target = getFieldByPath({ fields: collectionConfig.flattenedFields, path: joinField.on })
  if (!target) {
    throw new Error(`join field 'on'="${joinField.on}" does not resolve to any field on the collection`)
  }
  if (target.type !== 'relationship' && target.type !== 'upload') {
    throw new Error(`join 'on' must reference a relationship/upload field, got ${target.type}`)
  }
}

Type guard

function isValidJoinOn(target: unknown): target is { type: 'relationship' | 'upload' } {
  return typeof target === 'object' && target !== null &&
    ['relationship', 'upload'].includes((target as any).type)
}

Try / catch

try {
  await payload.find({ collection: 'posts', where: { 'comments.text': { like: 'x' } } })
} catch (e) {
  if (e instanceof APIError && e.message === 'Relationship field was not found') {
    console.error('join field on= points to a missing relationship — fix the collection config')
  }
  throw e
}

Prevention

When it happens

Trigger: A collection has a join field whose `on` value does not match any relationship field path in flattenedFields — e.g. the referenced relationship field was renamed/removed, or `on` was typed wrong.

Common situations: Renaming a relationship field without updating the join field's `on`; pointing `on` at a non-relationship field (group/array); config imported from another collection where the field does not exist.

Related errors


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