payloadcms/payload · error · MissingEditorProp

RichText field${field.name ? ` "${field.name}"` : ''} is mis

Error message

RichText field${field.name ? ` "${field.name}"` : ''} is missing the editor prop. For sub-richText fields, the editor props is required, as it would otherwise create infinite recursion.

What it means

Thrown during client-field sanitization when a `richText` field has no `editor` property. Payload requires every richText field to declare its editor (e.g. the Lexical adapter) because, unlike top-level fields which can fall back to a default editor, sub-fields (nested in blocks/arrays/tabs) have no default — omitting it would recurse infinitely building the field tree. `MissingEditorProp` aborts sanitization to prevent that.

Source

Thrown at packages/payload/src/fields/config/client.ts:387

              value: option.value,
            }
          } else if (typeof option === 'object') {
            field.options[i] = {
              label: option.label,
              value: option.value,
            }
          } else if (typeof option === 'string') {
            field.options[i] = option
          }
        }
      }

      break
    }

    case 'richText': {
      if (!incomingField?.editor) {
        throw new MissingEditorProp(incomingField) // while we allow disabling editor functionality, you should not have any richText fields defined if you do not have an editor
      }

      if (typeof incomingField?.editor === 'function') {
        throw new Error('Attempted to access unsanitized rich text editor.')
      }

      break
    }

    case 'tabs': {
      const field = clientField as unknown as TabsFieldClient

      if (incomingField.tabs?.length) {
        field.tabs = []

        for (let i = 0; i < incomingField.tabs.length; i++) {
          const tab = incomingField.tabs[i]
          const clientTab = {} as unknown as TabsFieldClient['tabs'][0]

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Pass the same editor adapter to every richText field: `import { RichTextAdapter } ... { type: 'richText', editor: lexicalEditor }`.
  2. Configure a top-level default editor in `buildConfig({ richText })` so top-level fields inherit it, and explicitly pass it to nested sub-fields.
  3. Remove richText fields you do not intend to use.

Example fix

// before
{ type: 'richText', name: 'body' } // nested in a block -> throws
// after
import { LexicalRichTextAdapter } from '@payloadcms/richtext-lexical'
{ type: 'richText', name: 'body', editor: new LexicalRichTextAdapter({ features: [] }) }
Defensive patterns

Strategy: type-guard

Validate before calling

function assertRichTextEditors(fields: Field[]) {
  for (const f of fields) {
    if (f.type === 'richText' && !f.editor) {
      throw new Error(`richText field '${f.name}' is missing the required editor prop`)
    }
    if ((f.type === 'array' || f.type === 'blocks') && 'fields' in f) assertRichTextEditors(f.fields as Field[])
  }
}

Type guard

function richTextHasEditor(f: any): boolean {
  return f?.type !== 'richText' || (typeof f?.editor === 'object' && f.editor !== null)
}

Prevention

When it happens

Trigger: Defining `{ type: 'richText' }` inside a block or array without an `editor`; nesting richText fields and forgetting the adapter on inner ones; removing the top-level richText editor plugin while keeping richText fields.

Common situations: Adding richText to a reusable block field; splitting content into nested richText sub-fields; installing Payload without wiring `richText` in `buildConfig` (no default editor).

Related errors


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