octobercms/october · error · Error

Broken JSON ${str[pos] === "{" ? "object" : "array"} body ne

Error message

Broken JSON ${str[pos] === "{" ? "object" : "array"} body near ${body}

What it means

When getBody() reaches an object or array value, it runs a bracket-matching scan using a stack that also tracks embedded quotes. This specific throw fires when a closing '}' arrives while the innermost open bracket on the stack is not '{' — a mismatched close. The message names 'object' or 'array' according to the composite being scanned and echoes everything consumed so far.

Source

Thrown at modules/system/assets/js/framework.js:2287

            if (stack[stack.length - 1] === '"') {
              stack.pop();
            } else if (stack[stack.length - 1] !== "'") {
              stack.push(str[i]);
            }
          } else if (str[i] === "'") {
            if (stack[stack.length - 1] === "'") {
              stack.pop();
            } else if (stack[stack.length - 1] !== '"') {
              stack.push(str[i]);
            }
          } else if (stack[stack.length - 1] !== '"' && stack[stack.length - 1] !== "'") {
            if (str[i] === "{") {
              stack.push("{");
            } else if (str[i] === "}") {
              if (stack[stack.length - 1] === "{") {
                stack.pop();
              } else {
                throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body);
              }
            } else if (str[i] === "[") {
              stack.push("[");
            } else if (str[i] === "]") {
              if (stack[stack.length - 1] === "[") {
                stack.pop();
              } else {
                throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body);
              }
            }
          }
          if (!stack.length) {
            return {
              originLength: i - pos,
              body
            };
          }
        }

View on GitHub (pinned to b608633a7e)

Solutions

  1. Fix the bracket order at the reported position — the 'near ...' body shows the scan up to the mismatched '}'.
  2. Validate complex nested values with JSON.parse in the console first (adding quotes to keys/strings) before pasting into the attribute.
  3. For deeply nested data prefer moving it out of the attribute (e.g. a hidden input or AJAX fetch) instead of inline JSON.

Example fix

// before
<div data-request-data="{ops: [1,2}}}">...</div>

// after
<div data-request-data="{ops: [1,2]}">...</div>
Defensive patterns

Strategy: validation

Validate before calling

// Cheap bracket-order check on the raw value (ignores quoted content)
function bracketsBalanceInOrder(value) {
    var stack = [], pairs = {'}': '{', ']': '['};
    for (var i = 0; i < value.length; i++) {
        var ch = value[i];
        if (ch === '{' || ch === '[') stack.push(ch);
        else if (pairs[ch]) { if (stack.pop() !== pairs[ch]) return false; }
    }
    return stack.length === 0;
}

Prevention

When it happens

Trigger: oc.parseJSON("{'a': [1, 2}}") — the '}' closes while '[' is innermost; an attribute like data-request-data="{ops: [1,2}}}"; any swapped/redundant closing brace inside an inline object/array value.

Common situations: Hand-written nested inline JSON in data attributes where brackets are closed in the wrong order; template concatenation that appends a stray '}' when conditionally building attribute values.

Related errors


AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21). Data as JSON: /api/errors/5f0a05acd0400457. Report an issue: GitHub.