{"record":{"id":"6979ebbd3e4cd44b","repo":"zloirock/core-js","slug":"unexpected-extra-character-chr-after-the-par","errorCode":null,"errorMessage":"Unexpected extra character: \"${chr}\" after the parsed data at: ${endIndex}","messagePattern":"Unexpected extra character: \"(.+?)\" after the parsed data at: (.+?)","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/core-js/modules/es.json.parse.js","lineNumber":46,"sourceCode":"var exec = uncurryThis(/./.exec);\nvar push = uncurryThis([].push);\n\nvar IS_DIGIT = /^\\d$/;\nvar IS_NON_ZERO_DIGIT = /^[1-9]$/;\nvar IS_NUMBER_START = /^[\\d-]$/;\nvar IS_WHITESPACE = /^[\\t\\n\\r ]$/;\n\nvar PRIMITIVE = 0;\nvar OBJECT = 1;\n\nvar $parse = function (source, reviver) {\n  source = toString(source);\n  var context = new Context(source, 0);\n  var root = context.parse();\n  var value = root.value;\n  var endIndex = context.skip(IS_WHITESPACE, root.end);\n  if (endIndex < source.length) {\n    throw new SyntaxError('Unexpected extra character: \"' + at(source, endIndex) + '\" after the parsed data at: ' + endIndex);\n  }\n  return isCallable(reviver) ? internalize({ '': value }, '', reviver, root) : value;\n};\n\nvar internalize = function (holder, name, reviver, node) {\n  var val = holder[name];\n  var unmodified = node && val === node.value;\n  var context = unmodified && typeof node.source == 'string' ? { source: node.source } : {};\n  var elementRecordsLen, keys, len, i, P;\n  if (isObject(val)) {\n    var nodeIsArray = isArray(val);\n    var nodes = unmodified ? node.nodes : nodeIsArray ? [] : {};\n    if (nodeIsArray) {\n      elementRecordsLen = nodes.length;\n      len = lengthOfArrayLike(val);\n      for (i = 0; i < len; i++) {\n        internalizeProperty(val, i, internalize(val, '' + i, reviver, i < elementRecordsLen ? nodes[i] : undefined));\n      }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/zloirock/core-js/blob/84e45fba098dd3a177d5cf2247d06ab8e98d3790/packages/core-js/modules/es.json.parse.js#L28-L64","documentation":"This SyntaxError is thrown by the core-js JSON.parse polyfill ($parse) when, after successfully parsing a complete JSON value, additional non-whitespace characters remain in the input. Native JSON.parse reports this as 'Unexpected non-whitespace character after JSON'; core-js names the offending character and index explicitly.","triggerScenarios":"Calling JSON.parse() with a string like '{\"a\":1} {\"b\":2}', '{\"a\":1};', a JSON body with trailing garbage, or concatenated JSON documents (NDJSON passed as one string). The check is endIndex < source.length after skipping whitespace past root.end.","commonSituations":"Server responses that append debug output or HTML after JSON (e.g. PHP warnings before/after the body); concatenating multiple JSON objects instead of parsing line-by-line; trailing semicolons or commas copied from code; reading a file that contains multiple JSON documents.","solutions":["Trim the input and ensure it contains exactly one JSON document; strip trailing garbage before parsing","For multiple JSON documents, split on newlines and JSON.parse each line (NDJSON handling)","Inspect the reported endIndex/at character to find where the extra content starts and fix the producer of the string","If the response may contain HTML error pages, check Content-Type and status before parsing"],"exampleFix":"// before\nconst data = JSON.parse(rawBody);\n// after\nconst data = JSON.parse(rawBody.trim());\n// or for NDJSON:\nconst items = rawBody.trim().split('\\n').map(line => JSON.parse(line));","handlingStrategy":"try-catch","validationCode":"function isSingleJsonDocument(s) {\n  if (typeof s !== 'string') return false;\n  try { JSON.parse(s); return true; } catch { return false; }\n}\n// cheap pre-check: only whitespace may follow the last plausible terminator\nfunction looksLikeSingleJson(s) {\n  const t = s.trim();\n  return /^[\\[{\"\\-0-9tfn]/.test(t) && /\\}$|\\]$|\"$|\\d$|e$|l$/.test(t);\n}","typeGuard":"function parsesAsJson(v) {\n  if (typeof v !== 'string') return false;\n  try { JSON.parse(v); return true; } catch { return false; }\n}","tryCatchPattern":"let value;\ntry {\n  value = JSON.parse(raw);\n} catch (e) {\n  if (e instanceof SyntaxError && /extra character/.test(e.message)) {\n    const idx = Number(e.message.match(/at: (\\d+)$/)?.[1] ?? NaN);\n    value = JSON.parse(raw.slice(0, idx)); // salvage the first document\n  } else throw e;\n}","preventionTips":["Trim whitespace and strip BOM before parsing","Check response Content-Type is application/json and status is 2xx before parsing","Treat multi-document payloads as NDJSON: split on newlines and parse each line","Never concatenate JSON documents into one string"],"tags":["json","syntax-error","parsing","trailing-data"],"backgroundTag":"unexpected-token-after-json","analyzedSha":"84e45fba098dd3a177d5cf2247d06ab8e98d3790","analyzedAt":"2026-08-30T20:36:10.323Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}