payloadcms/payload · error · APIError

${value} is not allowed as a JSON query value

Error message

${value} is not allowed as a JSON query value

What it means

A 400 `APIError` from `sanitizeValue` inside `createJSONQuery`: a query value used against a JSON/JSONB column (arrays, `json`, `richText`, localized JSON paths) failed the strict `SAFE_STRING_REGEX` (`/^[\w @.\-+:]*$/`). The regex is an allow-list that prevents SQL/JSONPath injection when interpolating values into raw `jsonb_path_exists(...)` SQL, so anything outside word chars, space, `@ . - + :` is rejected.

Source

Thrown at packages/drizzle/src/postgres/createJSONQuery/index.ts:32

  not_in: 'in',
  not_like: '!like_regex',
}

const sanitizeValue = (value: unknown, operator?: string): string => {
  if (value === null) {
    return `NULL`
  }

  if (typeof value === 'number' || typeof value === 'boolean') {
    return `${value}`
  }

  if (typeof value !== 'string') {
    throw new Error('Invalid value type')
  }

  if (!SAFE_STRING_REGEX.test(value)) {
    throw new APIError(`${value} is not allowed as a JSON query value`, 400)
  }

  const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')

  const prefix = ['like', 'not_like'].includes(operator ?? '') ? '(?i)' : ''

  return `"${prefix}${escaped}"`
}

export const createJSONQuery = ({ column, operator, pathSegments, value }: CreateJSONQueryArgs) => {
  const columnName = typeof column === 'object' ? column.name : column
  const jsonPaths = pathSegments
    .slice(1)
    .map((key) => {
      return `${sanitizePathSegment(key)}[*]`
    })
    .join('.')

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Sanitize/strip user input to safe characters before sending it as a `where` query value against array/json fields.
  2. For free-text search, prefer a dedicated text/textarea field (parameterized `like`) instead of querying raw JSON.
  3. If the value legitimately contains punctuation, perform the filter in application code after fetching, or store the searchable value in a normal column.
  4. If you need accent-insensitive matching on text, use the `unaccent` operator handler against a text column rather than a JSON path.

Example fix

// before: payload.find({ collection: 'pages', where: { 'meta.tags': { contains: 'C++ (API)' } } })
//  -> throws '<value> is not allowed as a JSON query value'
// after: strip unsafe characters, or move tags to a relationship/text field
const safe = userInput.replace(/[^\w @.\-+:]/g, '')
await payload.find({ collection: 'pages', where: { 'meta.tags': { contains: safe } } })
Defensive patterns

Strategy: validation

Validate before calling

// Validate JSON-query values against the same allow-list before sending
const SAFE = /^[\w @.\-+:]*$/
function safeJsonValue(v) {
  if (v === null || typeof v === 'number' || typeof v === 'boolean') return v
  if (typeof v === 'string') {
    if (!SAFE.test(v)) throw new Error(`Unsafe JSON query value: ${v}`)
    return v
  }
  throw new Error('Invalid JSON query value type')
}
const clean = safeJsonValue(userInput)
await payload.find({ collection, where: { 'meta.tags': { contains: clean } } })

Type guard

const isSafeJsonQueryString = (v: unknown): v is string =>
  typeof v === 'string' && /^[\w @.\-+:]*$/.test(v)

Try / catch

try {
  await payload.find({ collection, where: { 'meta.tags': { contains: q } } })
} catch (err) {
  if (err?.statusCode === 400 && /not allowed as a JSON query value/.test(err.message)) {
    return res.status(400).json({ error: 'Search contains unsupported characters.' })
  }
  throw err
}

Prevention

When it happens

Trigger: Querying an array/json field with `contains`/`like`/`equals`/`in` and a value containing punctuation or symbols not in the allow-list — e.g. quotes, parentheses, commas, `<`, `&`, emoji, or accented/non-ASCII letters. Triggers through the Payload REST/local API `where` query on array/JSON fields when `pathSegments.length > 1` (nested JSON path).

Common situations: Free-text search boxes feeding `contains` against an array/json field with user input containing punctuation; querying richText; localized JSON field queries with special characters; data containing accented characters that the ASCII-only word class rejects.

Related errors


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