← Todos os artigos

Unexpected End of JSON Input: por que acontece e como corrigir

O parser chegou ao fim da string antes de a estrutura estar completa. As causas vão de respostas de API truncadas a colchetes não fechados e strings vazias. Cinco padrões, cinco correções.

SyntaxError: Unexpected end of JSON input significa que o parser chegou ao fim da string antes de a estrutura JSON estar completa. Os dados foram cortados. Este artigo mostra cada forma comum em que isso acontece e exatamente como corrigir cada uma.

O que o erro significa

JSON.parse() é uma máquina de estados. Lê caractere por caractere, acompanhando colchetes, chaves e delimitadores de string abertos. Quando chega ao fim da entrada ainda „dentro de“ algo —— um objeto, array ou string —— ele dispara:

SyntaxError: Unexpected end of JSON input

O erro não dá número de linha nem posição porque o problema é a ausência de conteúdo —— não há para onde apontar.

Causa 1 —— Resposta de API truncada

A causa mais comum no mundo real. O servidor enviou um corpo JSON grande e a rede caiu cedo, a resposta foi lida antes de terminar, ou um limite de buffering de proxy/CDN foi atingido.

// O que chegou (conexão caiu no meio da resposta):
'{"users":[{"id":1,"name":"Ada"},{"id":2,"na'

JSON.parse('{"users":[{"id":1,...') // SyntaxError: Unexpected end of JSON input

Correção: Verifique o código HTTP e o cabeçalho Content-Length. Logue o tamanho do corpo bruto antes do parse. Se você usa fetch, sempre await response.json() em vez de ler response.text() e parsear na mão —— o parser JSON do navegador dá um erro mais claro em truncamento.

// Correto
const data = await response.json();

// Frágil —— esconde erros de truncamento
const text = await response.text();
const data = JSON.parse(text);

Causa 2 —— Objeto ou array não fechado

O JSON foi escrito à mão ou gerado por código que esqueceu um colchete ou chave de fechamento.

JSON.parse('{"name":"Ada","plan":"pro"')
// Falta o } de fechamento
// SyntaxError: Unexpected end of JSON input

JSON.parse('[1, 2, 3')
// Falta o ] de fechamento
// SyntaxError: Unexpected end of JSON input

Correção: Use um linter JSON ou cole a string no JSON Fix —— ele identifica o delimitador não fechado e, em modo leniente, pode adicionar o colchete que falta automaticamente.

Causa 3 —— String não fechada

Um valor string que nunca terminou com aspas duplas de fechamento, muitas vezes porque o valor em si continha uma aspa dupla não escapada:

JSON.parse('{"title":"He said "hello" to her"}')
//                              ^ aspa sem escape fecha a string cedo
// SyntaxError: Unexpected end of JSON input

// Correto —— escape aspas internas com barra invertida:
JSON.parse('{"title":"He said \"hello\" to her"}')

Correção: Escape aspas duplas internas como \", ou use JSON.stringify() para construir o JSON desde o começo em vez de montar strings na mão.

Causa 4 —— String vazia

Passar uma string vazia ou só com whitespace para JSON.parse() dispara o mesmo erro —— não há entrada para parsear.

JSON.parse('')   // SyntaxError: Unexpected end of JSON input
JSON.parse('  ') // SyntaxError: Unexpected end of JSON input
JSON.parse()     // SyntaxError: Unexpected token u… (undefined casteado para string)

Isso acontece muito quando um campo de formulário, chave do localStorage ou variável de ambiente está vazia.

// Guard antes do parse
const raw = localStorage.getItem('session');
if (!raw) return null;
return JSON.parse(raw);

Causa 5 —— Leitura de resposta em streaming cedo demais

Ao consumir uma API em streaming ou WebSocket, é fácil tentar parsear um chunk antes que a mensagem completa tenha chegado.

// ❌ Tentando parsear um chunk incompleto
ws.onmessage = (event) => {
  const data = JSON.parse(event.data); // pode estar parcial
};

// ✓ Buffer até o limite de mensagem (framing em nível de aplicação)
let buffer = '';
ws.onmessage = (event) => {
  buffer += event.data;
  if (buffer.endsWith('\n')) {        // ou verifique um delimitador conhecido
    const data = JSON.parse(buffer.trim());
    buffer = '';
  }
};

Diagnosticar truncamento: Content-Length e o leitor de streaming

Duas técnicas concretas para confirmar se a resposta foi mesmo cortada:

  • Compare com Content-Length. Se o servidor definiu, dá para detectar leitura curta diretamente:
    const res = await fetch(url);
    const expected = Number(res.headers.get('Content-Length') ?? NaN);
    const text = await res.text();
    if (Number.isFinite(expected) && text.length !== expected) {
      throw new Error(`truncated: got ${text.length} of ${expected} bytes`);
    }

    Nota: Content-Length pode estar ausente em respostas chunked/comprimidas.

  • Leia com o body reader de streaming. Usar res.body.getReader() deixa você observar a chegada chunk por chunk e notar quando o stream fecha no meio do payload —— sintoma de conexão caída ou timeout de proxy. O navegador expõe a falha de rede subjacente como rejeição do fetch se o stream abortar; combine com o erro do parser para confirmar.

Checklist rápido de diagnóstico

  • Logue typeof input e input.length logo antes da chamada de parse.
  • Se o tamanho parecer curto demais, a resposta foi truncada —— olhe os logs de rede.
  • Se o tamanho for 0, a fonte (API, storage, variável de ambiente) não retornou nada —— adicione um guard.
  • Se o tamanho parecer certo, cole a string no JSON Fix para encontrar o problema estrutural.

Recupere com elegância em produção

function safeParse(text, fallback = null) {
  if (!text || !text.trim()) return fallback;
  try {
    return JSON.parse(text);
  } catch {
    console.error('JSON parse failed, input length:', text.length);
    return fallback;
  }
}

Perguntas frequentes

O que causa „Unexpected end of JSON input“?

O parser chegou ao fim da string ainda dentro de um objeto, array ou string —— os dados estavam incompletos. A causa mais comum na vida real é uma resposta de API truncada; outras são colchete não fechado, string não terminada ou string vazia.

Por que não há número de linha ou posição?

Porque o problema é conteúdo faltando, não um caractere errado. Não há para onde o parser apontar —— ele simplesmente acabou a entrada antes de fechar a estrutura.

Como corrijo para uma string vazia?

Coloque um guard antes do parse: if (!raw || !raw.trim()) return fallback;. Campos de formulário vazios, chaves localStorage ausentes e variáveis de ambiente não definidas são as fontes habituais.

Como lido com isso elegantemente em produção?

Envolva JSON.parse() em um helper safeParse que retorne um fallback em caso de falha (veja o snippet acima), e logue o tamanho da entrada para distinguir truncamento de estrutura malformada. Para o conjunto completo de padrões, veja lidando com JSON quebrado em JavaScript.

Conserte JSON truncado no seu navegador

Tem uma string JSON quebrada para inspecionar ou reparar? JSON Fix no fixjson.org parseia, valida e auto-repara erros estruturais comuns —— incluindo colchetes faltando —— diretamente no navegador, sem enviar dados a nenhum servidor.