{"record":{"id":"b5c3ca1cf60ace95","repo":"zloirock/core-js","slug":"unterminated-array-at-i","errorCode":null,"errorMessage":"Unterminated array at: ${i}","messagePattern":"Unterminated array at: (.+?)","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/core-js/modules/es.json.parse.js","lineNumber":192,"sourceCode":"      if (at(source, i) === ']' && !expectElement) {\n        i++;\n        closed = true;\n        break;\n      }\n      var result = this.fork(i).parse();\n      push(nodes, result);\n      push(array, result.value);\n      i = this.until([',', ']'], result.end);\n      if (at(source, i) === ',') {\n        expectElement = true;\n        i++;\n      } else if (at(source, i) === ']') {\n        i++;\n        closed = true;\n        break;\n      }\n    }\n    if (!closed) throw new SyntaxError('Unterminated array at: ' + i);\n    return this.node(OBJECT, array, this.index, i, nodes);\n  },\n  string: function () {\n    var index = this.index;\n    var parsed = parseJSONString(this.source, this.index + 1);\n    return this.node(PRIMITIVE, parsed.value, index, parsed.end);\n  },\n  number: function () {\n    var source = this.source;\n    var startIndex = this.index;\n    var i = startIndex;\n    if (at(source, i) === '-') i++;\n    if (at(source, i) === '0') i++;\n    else if (exec(IS_NON_ZERO_DIGIT, at(source, i))) i = this.skip(IS_DIGIT, i + 1);\n    else throw new SyntaxError('Failed to parse number at: ' + i);\n    if (at(source, i) === '.') {\n      var fractionStartIndex = i + 1;\n      i = this.skip(IS_DIGIT, fractionStartIndex);","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/zloirock/core-js/blob/84e45fba098dd3a177d5cf2247d06ab8e98d3790/packages/core-js/modules/es.json.parse.js#L174-L210","documentation":"Thrown by the array() parser of the core-js JSON.parse polyfill when the end of the input is reached while scanning an array without finding the closing ']'. The array was opened with '[' but never terminated.","triggerScenarios":"JSON.parse() with input like '[1,2,3' or '[' — input ends (or nesting consumed the rest) before a matching ']' appears.","commonSituations":"Truncated API responses or chunked bodies cut mid-transfer; streaming/paginated JSON assembled incorrectly; files written incrementally before completion and read too early; manual string building of arrays missing the final ']'.","solutions":["Verify the input string is complete and balanced before parsing (count brackets or log the tail)","Retry the fetch/request if the body length is less than Content-Length, indicating truncation","Build arrays as real JS arrays and serialize with JSON.stringify rather than concatenating strings","For streamed JSON, buffer until the document is fully received, then parse once"],"exampleFix":"// before\nconst data = JSON.parse(await res.text()); // body cut off mid-array\n// after\nconst text = await res.text();\nconst expected = Number(res.headers.get('content-length'));\nif (expected && text.length !== expected) throw new Error('truncated response');\nconst data = JSON.parse(text);","handlingStrategy":"validation","validationCode":"function isCompleteJsonArray(s) {\n  if (typeof s !== 'string') return false;\n  const t = s.trim();\n  if (!t.startsWith('[')) return false;\n  try { JSON.parse(t); return true; } catch { return false; }\n}\nif (!isCompleteJsonArray(body)) throw new Error('incomplete JSON array');","typeGuard":"function isBalancedBrackets(s) {\n  if (typeof s !== 'string') return false;\n  let depth = 0, inStr = false, esc = false;\n  for (const c of s) {\n    if (esc) { esc = false; continue; }\n    if (c === '\\\\' && inStr) { esc = true; continue; }\n    if (c === '\"') inStr = !inStr;\n    else if (!inStr) {\n      if (c === '[') depth++;\n      if (c === ']') depth--;\n      if (depth < 0) return false;\n    }\n  }\n  return depth === 0 && !inStr;\n}","tryCatchPattern":"let items;\ntry {\n  items = JSON.parse(body);\n} catch (e) {\n  if (e instanceof SyntaxError && /Unterminated array/.test(e.message)) {\n    throw new Error('JSON array truncated mid-transfer; refetch');\n  }\n  throw e;\n}","preventionTips":["Verify chunked/streamed bodies are fully consumed (check done flag / final chunk) before parsing","Validate bracket balance cheaply before JSON.parse on large payloads","Construct arrays in JS and serialize with JSON.stringify instead of building strings","Add integrity checks (Content-Length, checksums) on bulk JSON transfers"],"tags":["json","syntax-error","unterminated","truncated-input"],"backgroundTag":"unterminated-json","analyzedSha":"84e45fba098dd3a177d5cf2247d06ab8e98d3790","analyzedAt":"2026-08-30T20:36:10.323Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}