{"record":{"id":"e769abd950dd6ce7","repo":"octobercms/october","slug":"broken-json-boolean-body-near-str","errorCode":null,"errorMessage":"Broken JSON boolean body near ${str}","messagePattern":"Broken JSON boolean body near (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"modules/system/assets/js/framework-bundle.js","lineNumber":2263,"sourceCode":"        throw new Error(\"Broken JSON boolean body near \" + str.substr(0, pos + 10));\n      }\n      if (str[pos] === \"f\") {\n        if (str.indexOf(\"f\", pos) === pos) {\n          return {\n            originLength: \"false\".length,\n            body: \"false\"\n          };\n        }\n        throw new Error(\"Broken JSON boolean body near \" + str.substr(0, pos + 10));\n      }\n      if (str[pos] === \"n\") {\n        if (str.indexOf(\"null\", pos) === pos) {\n          return {\n            originLength: \"null\".length,\n            body: \"null\"\n          };\n        }\n        throw new Error(\"Broken JSON boolean body near \" + str.substr(0, pos + 10));\n      }\n      if (str[pos] === \"-\" || str[pos] === \"+\" || str[pos] === \".\" || str[pos] >= \"0\" && str[pos] <= \"9\") {\n        var body = \"\";\n        for (var i = pos; i < str.length; i++) {\n          if (str[i] === \"-\" || str[i] === \"+\" || str[i] === \".\" || str[i] >= \"0\" && str[i] <= \"9\") {\n            body += str[i];\n          } else {\n            return {\n              originLength: body.length,\n              body\n            };\n          }\n        }\n        throw new Error(\"Broken JSON number body near \" + body);\n      }\n      if (str[pos] === \"{\" || str[pos] === \"[\") {\n        var stack = [str[pos]];\n        var body = str[pos];","sourceCodeStart":2245,"sourceCodeEnd":2281,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/system/assets/js/framework-bundle.js#L2245-L2281","documentation":"Thrown by the lenient JSON parser built into October CMS's AJAX framework (JsonParser.getBody, reached via oc.parseJSON while reading data-* attributes such as data-request-data). When a bare (unquoted) token inside a value starts with 't' or 'n', the parser expects exactly the literals 'true' or 'null'; anything else aborts with this error, echoing the offending input fragment. Note the sibling 'f' branch contains a quirk (str.indexOf(\"f\", pos) === pos is always true), so bare f-words silently parse as false instead of throwing - only t/n words can trigger this message.","triggerScenarios":"oc.request(el) or oc.parseJSON on a value like {ok: tru}, {status: nope}, or data-request-data=\"{flag: nul}\" - a bare word starting with t or n that is not exactly true/null. Also reachable via data-request-update / data-request-query attribute values parsed with parseJson:true.","commonSituations":"Typos in hand-written data attributes (tru, nul, Null); template engines (Blade/Twig) interpolating a PHP value without quotes so it lands as a bare word; HTML entity encoding (&quot;) stripping the quotes around a word; content management authors editing partial markup who forget the relaxed syntax still requires quoting non-literal words.","solutions":["Quote the offending value in the attribute: change {flag: nope} to {flag: 'nope'} or strict {\"flag\": \"nope\"}","If the value must be a literal, spell it exactly: true, false, null","When generating the attribute server-side, emit strict JSON via json_encode/JSON.stringify instead of hand-concatenating","Wrap the failing oc.request()/oc.parseJSON() call in try/catch to log which element's attribute is broken (the message includes the raw fragment near the failure)"],"exampleFix":"<!-- before -->\n<button data-request=\"onSave\" data-request-data=\"{confirm: nope}\">Save</button>\n\n<!-- after -->\n<button data-request=\"onSave\" data-request-data=\"{confirm: 'nope'}\">Save</button>","handlingStrategy":"try-catch","validationCode":"// Pre-flight: bare t/n words must be the exact literals\nfunction checkBareTokens(attrValue) {\n  return !/(^|[\\[{,:\\s])(t(?!rue\\b)|n(?!ull\\b))[\\w.+-]*/.test(attrValue);\n}","typeGuard":null,"tryCatchPattern":"try {\n  oc.request(el, 'onSave');\n} catch (e) {\n  if (/Broken JSON boolean body/.test(e.message)) {\n    console.error('Bad keyword in', el.getAttribute('data-request-data'), e.message);\n    return;\n  }\n  throw e;\n}","preventionTips":["Quote every non-numeric, non-literal value in data-request-* attributes","Generate attribute values with JSON.stringify/json_encode, never by concatenation","Add a page-ready check that oc.parseJSON()s every data-request-data attribute and logs offenders"],"tags":["json","ajax","html-attribute","parser","frontend"],"backgroundTag":"invalid-json-attribute","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}