payloadcms/payload · error · InvalidConfiguration

Compound indexes within localized and non localized fields a

Error message

Compound indexes within localized and non localized fields are not supported in SQL. Expected ${path} to be ${someLocalized ? 'non' : ''} localized.

What it means

Thrown during schema build (build.ts) when a compound index spans both localized and non-localized fields. In the SQL adapter a localized field lives in a separate per-locale table while a non-localized field lives in the base table, so a single multi-column index cannot reference both. The adapter records the localized-ness of the first indexed field and rejects any subsequent field that differs.

Source

Thrown at packages/drizzle/src/schema/build.ts:305

    for (const index of compoundIndexes) {
      let someLocalized: boolean | null = null
      const columns: string[] = []

      const getTableToUse = () => {
        if (someLocalized) {
          return localesTable
        }

        return table
      }

      for (const { path, pathHasLocalized } of index.fields) {
        if (someLocalized === null) {
          someLocalized = pathHasLocalized
        }

        if (someLocalized !== pathHasLocalized) {
          throw new InvalidConfiguration(
            `Compound indexes within localized and non localized fields are not supported in SQL. Expected ${path} to be ${someLocalized ? 'non' : ''} localized.`,
          )
        }

        const columnPath = path.replaceAll('.', '_')

        if (!getTableToUse().columns[columnPath]) {
          throw new InvalidConfiguration(
            `Column ${columnPath} for compound index on ${path} was not found in the ${getTableToUse().name} table.`,
          )
        }

        columns.push(columnPath)
      }

      if (someLocalized) {
        columns.push('_locale')
      }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Make all fields in the compound index consistently localized or consistently non-localized.
  2. Split the index into two separate indexes: one over the localized fields, one over the non-localized fields.
  3. If you need a cross-cutting index, denormalize the data into a single field whose localization matches the rest of the index.

Example fix

// before
index: [{ fields: { title: true, slug: true } }] // title localized, slug not
// after
index: [{ fields: { title: true, description: true } }] // both localized
Defensive patterns

Strategy: validation

Validate before calling

function assertIndexLocalityConsistent(fields, localizedSet) {
  const localizations = Object.keys(fields).map(f => !!localizedSet[f])
  if (localizations.some(l => l !== localizations[0])) {
    throw new Error('Compound index mixes localized and non-localized fields')
  }
}

Prevention

When it happens

Trigger: Defining an index on a field group/array where `index: [{ fields: { title: true, value: true } }]` mixes a localized field (title) with a non-localized one (value), and one or both are localized.

Common situations: Enabling localization on one field of an indexed group after the index was already defined; copy-pasting an index config between localized and non-localized field definitions.

Related errors


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