payloadcms/payload · error · TypeError

JSONObject cannot represent non-object value: ${value}

Error message

JSONObject cannot represent non-object value: ${value}

What it means

Thrown by the `ensureObject` helper used as `parseValue` and `serialize` for the `JSONObject` GraphQL scalar. It fires whenever the value is not a plain object — i.e. it is not `typeof 'object'`, or is `null`, or is an array. The scalar intentionally only accepts JSON objects (not arrays or primitives), unlike the more permissive `JSON` scalar. This protects the schema contract that a `JSONObject` field is always a `{ }` value.

Source

Thrown at packages/graphql/src/packages/graphql-type-json/index.ts:10

import { GraphQLScalarType } from 'graphql'
import { Kind, print } from 'graphql/language/index.js'

function identity(value) {
  return value
}

function ensureObject(value) {
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
    throw new TypeError(`JSONObject cannot represent non-object value: ${value}`)
  }

  return value
}

function parseObject(typeName, ast, variables) {
  const value = Object.create(null)
  ast.fields.forEach((field) => {
    value[field.name.value] = parseLiteral(typeName, field.value, variables)
  })

  return value
}

function parseLiteral(typeName, ast, variables) {
  switch (ast.kind) {
    case Kind.BOOLEAN:
    case Kind.STRING:

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Send a plain object `{ }` instead of an array or primitive for the `JSONObject` argument.
  2. If arbitrary JSON (arrays/primitives) is legitimately needed, switch the schema field from `GraphQLJSONObject` to `GraphQLJSON`.
  3. Validate/coerce the value client-side: if `Array.isArray(v)` or `v === null` or `typeof v !== 'object'`, wrap or reject before sending.

Example fix

// before — mutation arg typed JSONObject, value is an array
variables: { filters: [{ field: 'x', op: 'eq' }] }

// after — wrap in an object
variables: { filters: { rules: [{ field: 'x', op: 'eq' }] } }
Defensive patterns

Strategy: type-guard

Validate before calling

function ensurePlainObject(v) {
  if (typeof v !== 'object' || v === null || Array.isArray(v)) {
    throw new Error('JSONObject argument must be a plain object')
  }
  return v
}

Type guard

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v)
}

Try / catch

try {
  await client.request(mutation, { input: ensurePlainObject(value) })
} catch (e) {
  if (e instanceof TypeError && /JSONObject cannot represent non-object/.test(e.message)) {
    // wrap arrays/primitives in an object or use the JSON scalar
  }
  throw e
}

Prevention

When it happens

Trigger: A GraphQL mutation/argument typed `JSONObject` receives a primitive (string/number/boolean), `null` (non-nullable), or an array in the variables. Also fires during serialization if a resolver returns an array or null for a `JSONObject` field.

Common situations: Confusing `JSON` (any JSON value) with `JSONObject` (object only); passing `[]` where a settings object is expected; a resolver returning `null` for a non-null JSONObject field; frontend sending `[1,2,3]` as JSON-stringified body for a field documented as an object.

Related errors


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