zloirock/core-js · error · SyntaxError

Unterminated array at: ${i}

Error message

Unterminated array at: ${i}

What it means

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.

Source

Thrown at packages/core-js/modules/es.json.parse.js:192

      if (at(source, i) === ']' && !expectElement) {
        i++;
        closed = true;
        break;
      }
      var result = this.fork(i).parse();
      push(nodes, result);
      push(array, result.value);
      i = this.until([',', ']'], result.end);
      if (at(source, i) === ',') {
        expectElement = true;
        i++;
      } else if (at(source, i) === ']') {
        i++;
        closed = true;
        break;
      }
    }
    if (!closed) throw new SyntaxError('Unterminated array at: ' + i);
    return this.node(OBJECT, array, this.index, i, nodes);
  },
  string: function () {
    var index = this.index;
    var parsed = parseJSONString(this.source, this.index + 1);
    return this.node(PRIMITIVE, parsed.value, index, parsed.end);
  },
  number: function () {
    var source = this.source;
    var startIndex = this.index;
    var i = startIndex;
    if (at(source, i) === '-') i++;
    if (at(source, i) === '0') i++;
    else if (exec(IS_NON_ZERO_DIGIT, at(source, i))) i = this.skip(IS_DIGIT, i + 1);
    else throw new SyntaxError('Failed to parse number at: ' + i);
    if (at(source, i) === '.') {
      var fractionStartIndex = i + 1;
      i = this.skip(IS_DIGIT, fractionStartIndex);

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Verify the input string is complete and balanced before parsing (count brackets or log the tail)
  2. Retry the fetch/request if the body length is less than Content-Length, indicating truncation
  3. Build arrays as real JS arrays and serialize with JSON.stringify rather than concatenating strings
  4. For streamed JSON, buffer until the document is fully received, then parse once

Example fix

// before
const data = JSON.parse(await res.text()); // body cut off mid-array
// after
const text = await res.text();
const expected = Number(res.headers.get('content-length'));
if (expected && text.length !== expected) throw new Error('truncated response');
const data = JSON.parse(text);
Defensive patterns

Strategy: validation

Validate before calling

function isCompleteJsonArray(s) {
  if (typeof s !== 'string') return false;
  const t = s.trim();
  if (!t.startsWith('[')) return false;
  try { JSON.parse(t); return true; } catch { return false; }
}
if (!isCompleteJsonArray(body)) throw new Error('incomplete JSON array');

Type guard

function isBalancedBrackets(s) {
  if (typeof s !== 'string') return false;
  let depth = 0, inStr = false, esc = false;
  for (const c of s) {
    if (esc) { esc = false; continue; }
    if (c === '\\' && inStr) { esc = true; continue; }
    if (c === '"') inStr = !inStr;
    else if (!inStr) {
      if (c === '[') depth++;
      if (c === ']') depth--;
      if (depth < 0) return false;
    }
  }
  return depth === 0 && !inStr;
}

Try / catch

let items;
try {
  items = JSON.parse(body);
} catch (e) {
  if (e instanceof SyntaxError && /Unterminated array/.test(e.message)) {
    throw new Error('JSON array truncated mid-transfer; refetch');
  }
  throw e;
}

Prevention

When it happens

Trigger: JSON.parse() with input like '[1,2,3' or '[' — input ends (or nesting consumed the rest) before a matching ']' appears.

Common situations: 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 ']'.

Related errors


AI-assisted analysis of zloirock/core-js@84e45fba09 (2026-08-30). Data as JSON: /api/errors/b5c3ca1cf60ace95. Report an issue: GitHub.