payloadcms/payload · error · APIError

Invalid field path.

Error message

Invalid field path.

What it means

In setNestedValue, getPathKey validates array indices. It throws APIError 'Invalid field path.' when an index is out of bounds: if a source array is provided and index >= source.length, or without a source when index > target.length + 1 (MAX_UNVERIFIED_SPARSE_ARRAY_GAP). This prevents creating huge sparse arrays from untrusted paths.

Source

Thrown at packages/plugin-import-export/src/utilities/setNestedValue.ts:34

  return Number.isSafeInteger(index) && index >= 0
}

const getPathKey = (
  target: Record<string, unknown> | unknown[],
  part: string,
  source: unknown,
): number | string => {
  if (!Array.isArray(target) || !isArrayIndex(part)) {
    return part
  }

  const index = Number(part)

  if (
    (Array.isArray(source) && index >= source.length) ||
    (!Array.isArray(source) && index > target.length + MAX_UNVERIFIED_SPARSE_ARRAY_GAP)
  ) {
    throw new APIError('Invalid field path.', 400, null, true)
  }

  return index
}

const getSourceValue = (source: unknown, part: string): unknown => {
  if (source === null || typeof source !== 'object') {
    return undefined
  }

  const key = Array.isArray(source) && isArrayIndex(part) ? Number(part) : part

  return (source as Record<number | string, unknown>)[key]
}

/**
 * Sets a value deeply into a nested object or array, based on a dot-notation path.
 *

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Validate array indices against the source array length before building the path.
  2. Reject/normalize indices that exceed target.length + 1 when no source is available.
  3. Sanitize untrusted paths to clamp out-of-range indices.
Defensive patterns

Strategy: validation

Validate before calling

function assertPathWithinSource(path: string, source: unknown) {
  const parts = path.split('.')
  let cur: unknown = source
  for (const p of parts) {
    if (Array.isArray(cur) && /^\d+$/.test(p) && Number(p) >= cur.length) {
      throw new Error(`Array index ${p} out of bounds (len ${cur.length})`)
    }
    cur = Array.isArray(cur) || (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)?.[p] : undefined
  }
}

Type guard

const isWithinArrayBounds = (index: number, source: unknown): boolean =>
  !Array.isArray(source) || index < source.length

Prevention

When it happens

Trigger: A dot path like 'items.999.field' where the source array is short (index >= source.length), or a large index with no source to validate against (exceeds the allowed sparse gap).

Common situations: Reconstructing nested objects from flattened CSV rows with array fields; untrusted path input with arbitrary indices; mismatch between source array length and the target path.

Related errors


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