Se você já trabalhou com JSON, com certeza esbarrou na temida mensagem SyntaxError: Unexpected token. Ela aparece no console do navegador, em respostas de API, em arquivos de configuração e em pipelines de CI/CD. O erro em si não ajuda muito: ele avisa que algo está errado, mas raramente explica o quê.
Se quiser ir direto para a correção, cole o seu JSON quebrado no JSON Formatter e ele vai destacar a linha e o caractere exatos onde o erro acontece. A partir daí, este guia percorre as causas mais comuns dos erros de parse de JSON, mostra exatamente como corrigir cada uma e oferece um fluxo de trabalho confiável para detectar esses problemas antes que causem dor de cabeça.
O que "Unexpected token" realmente significa?
Os parsers de JSON leem o texto caractere por caractere. Quando o parser encontra um caractere que não pertence ao formato segundo a especificação JSON, ele lança um SyntaxError. O "unexpected token" é simplesmente o caractere que o parser não esperava encontrar naquela posição.
Por exemplo, veja este JSON quebrado, em que o valor de um objeto usa aspa simples em vez de aspa dupla:
{
"name": "Alice",
"age": 30,
"city": 'Tokyo'
}
O V8 atual (o motor por trás do Chrome e do Node.js) reporta:
Unexpected token ''', ..." "city": 'Tokyo'
}" is not valid JSON
Em vez de um número de posição, a mensagem cita um trecho do texto ao redor do erro. Engines mais antigas reportavam um número de position (Unexpected token ' in JSON at position 14); a tabela de comparação mais adiante neste guia reúne as duas redações, porque ainda existe bastante material e resposta de Stack Overflow citando a antiga. De qualquer forma, contar caracteres manualmente em um arquivo JSON grande é cansativo. É aí que uma ferramenta como o JSON Formatter se torna indispensável: ela aponta visualmente o local do erro.
As 5 causas mais comuns de erros de parse de JSON
1. Vírgulas sobrando (trailing commas)
Esta talvez seja a causa mais frequente de erros de parse de JSON, especialmente para quem escreve JavaScript com frequência. Arrays e objetos em JavaScript aceitam tranquilamente vírgulas no final. JSON não.
A versão quebrada:
{
"name": "Alice",
"age": 30,
"city": "Tokyo",
}
A versão corrigida:
{
"name": "Alice",
"age": 30,
"city": "Tokyo"
}
A vírgula depois de "Tokyo" é o problema. O V8 atual reporta:
Expected double-quoted property name in JSON at position 53 (line 5 column 1)
O parser lê a vírgula, espera outro par chave-valor e, como o que vem em seguida é uma chave de fechamento em vez de uma chave entre aspas, reporta que esperava um nome de propriedade. Ele não chama a chave de "unexpected token", diferente de como engines mais antigas descreviam esse caso.
Vírgulas sobrando também aparecem em arrays:
{
"colors": ["red", "green", "blue",]
}
Aqui a mensagem segue o padrão "unexpected token":
Unexpected token ']', ..."", "blue",]
}" is not valid JSON
Diferente do caso do objeto, a vírgula sobrando do array deixa ] como o próximo caractere real, e o V8 reporta isso como unexpected token. Remova a vírgula depois de "blue" e o erro desaparece:
{
"colors": ["red", "green", "blue"]
}
Esse engano é tão fácil de cometer que muitos editores de código hoje têm uma opção para remover automaticamente as vírgulas sobrando ao salvar arquivos JSON. Se o seu editor oferece esse recurso, ative-o.
2. Aspas simples em vez de aspas duplas
JSON exige aspas duplas para todas as strings e chaves. Aspas simples não são válidas, mesmo que JavaScript e Python aceitem ambas para literais de string.
A versão quebrada:
{
'name': 'Alice',
'age': 30
}
A versão corrigida:
{
"name": "Alice",
"age": 30
}
Esse erro costuma surgir quando alguém copia um dicionário Python ou um objeto literal de JavaScript e tenta usá-lo como JSON. Os dois formatos parecem semelhantes, mas não são intercambiáveis.
Um simples find-and-replace de ' por " geralmente resolve, mas tome cuidado se os valores das suas strings contiverem apóstrofos. Nesse caso, você precisa escapá-los ou tratar a substituição com mais atenção. Colar o texto no JSON Formatter vai sinalizar as posições exatas onde aparecem aspas simples, para que você possa corrigi-las uma a uma.
3. Chaves sem aspas
Em JavaScript, as chaves de um objeto não precisam de aspas se forem identificadores válidos. Em JSON, toda chave precisa ser uma string entre aspas duplas, sem exceções.
A versão quebrada:
{
name: "Alice",
age: 30
}
A versão corrigida:
{
"name": "Alice",
"age": 30
}
Isso costuma acontecer quando alguém escreve JSON à mão ou copia de um código-fonte JavaScript. Também aparece em arquivos de configuração quando a pessoa esquece que o JSON é mais rígido do que a linguagem que costuma usar.
4. Comentários no JSON
JSON não suporta comentários. Nem comentários de uma linha (//), nem comentários de várias linhas (/* */), nem comentários com cerquilha (#). Se o parser encontrar qualquer um deles, ele lança um erro.
A versão quebrada:
{
// User's display name
"name": "Alice",
/* Age in years */
"age": 30
}
A versão corrigida:
{
"name": "Alice",
"age": 30
}
Esse é um incômodo real. É perfeitamente razoável querer comentários em um arquivo de configuração, e muitos desenvolvedores ficam frustrados por o JSON não permitir isso. Algumas ferramentas (como o settings.json do VS Code) na verdade usam um superconjunto chamado JSONC (JSON with Comments), mas os parsers de JSON padrão rejeitam comentários sem dó.
Para uma comparação lado a lado de JSONC, JSON5, campos _comment e scripts de remoção, e qual escolher para arquivos de config, dados ou API, veja JSON pode ter comentários?. Se você prefere abandonar o JSON de vez, o YAML suporta comentários nativamente com o caractere #, e dá para converter entre os dois formatos com facilidade. Confira nosso artigo de dicas de formatação de JSON para saber mais sobre como lidar com arquivos JSON complexos.
5. Caracteres BOM (Byte Order Mark)
Esse é traiçoeiro porque você não consegue ver o problema apenas olhando o arquivo. Um BOM é um caractere invisível (U+FEFF) que alguns editores de texto, especialmente no Windows, inserem bem no início de um arquivo. Ele informa ao editor qual codificação o arquivo usa.
O parser de JSON esbarra nesse caractere invisível antes de chegar ao { ou [ de abertura, e não faz ideia do que fazer com ele. O V8 atual reporta:
Unexpected token '', "{
"name"... is not valid JSON
Aquele caractere que parece em branco logo depois do primeiro ' é o BOM. Engines mais antigas reportavam Unexpected token in JSON at position 0 (position 0, porque o BOM é sempre o primeiro caractere do arquivo).
Como corrigir:
- Abra o arquivo em um editor hexadecimal e remova os três primeiros bytes (
EF BB BFpara o BOM de UTF-8). - No VS Code, clique no indicador de codificação na barra de status, escolha "Save with Encoding" e selecione "UTF-8" (sem BOM).
- Use uma ferramenta de linha de comando:
sed -i '1s/^\xEF\xBB\xBF//' file.json
O estado antes (mostrado em hexadecimal):
EF BB BF 7B 0A 20 20 22 6E 61 6D 65 22 ...
O estado depois:
7B 0A 20 20 22 6E 61 6D 65 22 ...
O conteúdo do arquivo parece idêntico em um editor de texto, mas agora o parser consegue lê-lo.
Outras causas que vale a pena conhecer
Além das cinco principais, aqui vão mais alguns problemas que costumam pegar as pessoas de surpresa:
Colchetes ou chaves desbalanceados
Um } ou ] de fechamento faltando vai causar um erro de parse, geralmente reportado no fim do arquivo. Se o seu JSON tem muitos níveis aninhados, encontrar o colchete desbalanceado a olho nu é quase impossível. Um formatador com correspondência de colchetes vai economizar bastante tempo.
Caracteres de controle dentro de strings
Quebras de linha, tabulações e outros caracteres de controle dentro de strings JSON precisam ser escapados. Uma quebra de linha literal dentro do valor de uma string não é válida:
{"message": "Hello
World"}
Deveria ser:
{"message": "Hello\nWorld"}
Números com zeros à esquerda
Números em JSON não podem ter zeros à esquerda. 007 não é JSON válido: precisa ser 7, ou 0.07, ou algum outro formato numérico padrão.
{
"code": 007
}
Corrigido:
{
"code": 7
}
Usar undefined ou NaN
O undefined e o NaN do JavaScript não são valores JSON válidos. Se você serializar um objeto que contém undefined, a maioria dos serializadores vai omitir a chave ou lançar um erro. NaN e Infinity são rejeitados da mesma forma.
Redação antiga x redação atual das mensagens de erro
Se você está depurando com um guia antigo, uma resposta do Stack Overflow em cache ou uma versão anterior deste artigo, e a redação não bate com o que aparece no seu console, é por isso: a redação das mensagens de erro do JSON.parse() mudou conforme as engines de JavaScript evoluíram. O restante deste guia usa a redação atual, mas a antiga continua valendo a pena manter pesquisável, porque ainda existe bastante material por aí que a cita.
Duas mudanças importam mais. Primeiro, as mensagens com token entre aspas (Unexpected token 'X', "..." is not valid JSON) não reportam mais nenhum número de position; em vez disso, citam um trecho do texto ao redor do erro. Segundo, as mensagens Expected ... in JSON at position N continuam reportando uma posição, mas agora também acrescentam (line L column C), algo que a redação antiga nunca trazia.
| Onde aparece neste guia | Redação antiga | Saída atual do V8 (medida) |
|---|---|---|
| Exemplo inicial (aspa simples) | Unexpected token ' in JSON at position 14 | Unexpected token ''', ..." "city": 'Tokyo'}" is not valid JSON |
| Causa 1: vírgula sobrando (objeto) | não citada no artigo (descrita como "a chave de fechamento vira o unexpected token") | Expected double-quoted property name in JSON at position 53 (line 5 column 1) |
| Causa 1: vírgula sobrando (array) | não citada no artigo (mesma descrição do caso do objeto) | Unexpected token ']', ..."", "blue",]}" is not valid JSON |
| Causa 3: chaves sem aspas | não citada no artigo | Expected property name or '}' in JSON at position 4 (line 2 column 3) |
| Causa 4: comentários | não citada no artigo | Expected property name or '}' in JSON at position 4 (line 2 column 3) |
| Causa 5: BOM | Unexpected token in JSON at position 0 | Unexpected token '', "{ "name"... is not valid JSON |
JSON.parse(undefined) | Unexpected token u in JSON at position 0 | "undefined" is not valid JSON |
JSON.parse({ name: "Alice" }) | Unexpected token o in JSON at position 1 | "[object Object]" is not valid JSON |
| Resposta HTML (tabela de ambientes mais abaixo) | Unexpected token < in JSON at position 0 | Unexpected token '<', "<!DOCTYPE html>" is not valid JSON |
Medimos cada string da coluna "atual" rodando JSON.parse() sobre os mesmos trechos de JSON usados ao longo deste guia, no Node v26.3.1 / V8 14.6. O script e a saída bruta estão commitados em scripts/benchmarks/json-parse-error-messages/ no repositório, então cada linha é reproduzível. Não verificamos em qual versão do V8 essa redação mudou: esta tabela só confirma o que o V8 atual reporta hoje.
Busca por sintoma: token u, token o e end of input
O caractere exato que aparece na mensagem de erro reduz bastante a causa. As três variantes abaixo apontam cada uma para um engano diferente, e nenhuma delas é um problema dentro do seu arquivo JSON: todas acontecem antes de o parser chegar a ver JSON válido de fato. (Se o token for <, o servidor retornou uma página HTML em vez de JSON; veja a tabela de ambientes mais abaixo.)
Unexpected token u in JSON at position 0
O JSON.parse recebeu a string "undefined" — o u é a primeira letra dela, e é por isso que engines mais antigas nomeavam o token u na mensagem. Isso quase sempre significa que o valor que você passou já era undefined antes do parse:
const raw = localStorage.getItem("settings"); // se a chave não existe, é null
JSON.parse(undefined); // lança SyntaxError: "undefined" is not valid JSON
O V8 atual cita a string convertida inteira ("undefined" is not valid JSON) em vez de nomear um único caractere. Verifique se o valor realmente existe antes de fazer o parse. Uma chamada de API que voltou sem corpo, uma chave de armazenamento inexistente ou um erro de digitação no nome de uma variável são as causas mais comuns.
Unexpected token o in JSON at position 1
O parser recebeu a string "[object Object]". A posição 0 é [, que parece o início de um array, então engines mais antigas reportavam falha no o da posição 1. Isso acontece quando você passa um objeto JavaScript — em vez de uma string JSON — para o JSON.parse, forçando uma conversão implícita para string:
const data = { name: "Alice" };
JSON.parse(data); // data vira "[object Object]"; lança SyntaxError: "[object Object]" is not valid JSON
O V8 atual cita a string convertida diretamente, em vez de nomear o caractere o. O valor já estava com parse feito. Use-o diretamente, ou, se a intenção era fazer uma cópia profunda, use structuredClone(data) em vez de um ciclo stringify/parse.
Unexpected end of JSON input
O parser ficou sem caracteres antes de o JSON estar completo. Os dois casos mais comuns são uma string vazia (JSON.parse("")) e uma resposta truncada: uma requisição de rede interrompida ou um arquivo escrito apenas parcialmente. Registre primeiro o tamanho da string bruta; se for 0, o bug está antes do parser, não no seu JSON.
Um fluxo de trabalho confiável para depurar JSON
Quando você se depara com um erro de parse e o arquivo tem mais do que algumas linhas, ficar encarando o texto bruto não é produtivo. Aqui está um fluxo de trabalho que funciona de forma consistente:
-
Cole o JSON no JSON Formatter. Ele vai mostrar o local exato do erro com um número de linha e uma descrição do que deu errado.
-
Observe a posição reportada. O erro geralmente está na posição que o parser indica, ou logo antes dela. Às vezes o engano real está algumas linhas antes: por exemplo, uma vírgula faltando na linha 10 pode só causar erro quando o parser chega à linha 11.
-
Verifique as cinco causas principais listadas acima. Na prática, vírgulas sobrando e aspas simples respondem pela maioria dos erros de parse do mundo real.
-
Se o arquivo foi gerado por código, verifique a etapa de serialização. Você está usando
JSON.stringify()ou uma função equivalente? Montar strings JSON à mão com concatenação de strings é uma fonte comum de bugs. -
Se o arquivo foi baixado ou recebido de uma API, verifique a codificação. Problemas de BOM, divergências de codificação de caracteres e respostas truncadas geram erros de parse.
Quando o JSON vem de uma chamada fetch, leia o texto bruto e o status antes de fazer o parse. Esse único padrão detecta páginas de erro HTML, corpos vazios e respostas truncadas em um só lugar:
const response = await fetch("/api/data");
const raw = await response.text(); // lê como texto primeiro, não response.json()
if (!response.ok) {
console.error(`HTTP ${response.status}:`, raw.slice(0, 200));
} else if (!raw) {
console.error("Corpo da resposta vazio"); // o clássico "Unexpected end of JSON input"
} else {
try {
const data = JSON.parse(raw);
} catch (e) {
console.error("Falha no parse do JSON:", e.message, raw.slice(0, 200));
}
}
Erros de parse em diferentes ambientes
As mensagens de erro variam de plataforma para plataforma, o que pode tornar confusa a busca por soluções.
| Ambiente / runtime | Mensagem de erro típica | O que ela indica |
|---|---|---|
| Chrome / Node.js (V8) | Unexpected token '<', "<!DOCTYPE html>" is not valid JSON | Um < no início significa que o servidor retornou uma página HTML em vez de JSON: verifique a aba de rede |
| Firefox (SpiderMonkey) | SyntaxError: JSON.parse: unexpected character | O MDN documenta os erros do JSON.parse() nesse formato JSON.parse: <motivo> (JSON_bad_parseAbre em uma nova aba). A referência não diz a qual engine cada redação corresponde, então trate isso como o formato documentado, não como uma string confirmada diretamente contra o SpiderMonkey |
| Python | json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 3 column 5 | Dá tanto o número da linha quanto o da coluna |
| Java (Jackson) | JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name | Verboso, mas específico sobre o que esperava encontrar em comparação com o que de fato encontrou |
Se você ver uma mensagem assim no navegador (a forma atual do V8 Unexpected token '<', "<!DOCTYPE html>" is not valid JSON, a antiga Unexpected token < in JSON at position 0, ou a forma JSON.parse: unexpected character no Firefox), o servidor quase certamente retornou uma página de erro HTML (uma página 404 ou 500) em vez de JSON. Suspeite da URL da requisição ou do status code, não da sintaxe do seu JSON.
Como evitar erros de parse desde o início
Em vez de corrigir os erros depois que acontecem, alguns hábitos podem eliminar a maior parte dos erros de parse de JSON:
- Use
JSON.stringify()para produzir JSON, e não concatenação de strings. Isso vale para qualquer linguagem: use o serializador embutido. - Configure seu editor para validar JSON ao salvar. VS Code, IntelliJ e Sublime Text têm validação de JSON embutida ou disponível como plugin.
- Adicione uma etapa de lint ao seu pipeline de CI. Uma checagem simples como
python -m json.tool < config.jsondetecta arquivos malformados antes que cheguem à produção. - Ao editar JSON à mão, use uma ferramenta com validação em tempo real. O JSON Formatter valida enquanto você digita e mostra os erros imediatamente.
Tome cuidado com ferramentas online que você não controla: colar dados de trabalho em um conversor não confiável pode expor informações sensíveis do arquivo. Veja os conversores online são seguros? para saber como distinguir quais processam os dados localmente. O JSON Formatter da FormatArc roda inteiramente no seu navegador e nunca envia seus dados.
Para mais sobre como escrever JSON limpo, veja nossas dicas de formatação de JSON e o guia de sintaxe de JSON. Se você encontrar erros de parse ao depurar respostas de API com curl, nosso guia para formatar a saída JSON do curl mostra como detectar respostas malformadas no terminal antes que cheguem ao seu código.
Quando o JSON não é o formato certo
Se você se vê brigando com as limitações do JSON com frequência, querendo comentários, precisando de strings de várias linhas ou lidando com configurações aninhadas complexas, pode valer a pena considerar o YAML como alternativa. O YAML suporta comentários, lida naturalmente com texto de várias linhas e costuma ser mais legível para arquivos de configuração.
O custo dessa escolha é que o YAML é sensível à indentação e tem suas próprias armadilhas (coerção implícita de tipos, por exemplo). Mas, para arquivos de configuração em que pessoas precisam ler e editar o conteúdo, o YAML costuma ser a opção mais prática. Você sempre pode converter entre os dois formatos quando necessário: veja nosso guia sobre as diferenças entre YAML e JSON para uma comparação mais aprofundada.
Para concluir
Os erros de parse de JSON são irritantes, mas previsíveis. As mesmas cinco ou seis causas respondem pela grande maioria dos casos:
- Vírgulas sobrando
- Aspas simples
- Chaves sem aspas
- Comentários
- Caracteres BOM
- Colchetes desbalanceados
Familiarize-se com esses padrões e você vai corrigir a maioria dos erros de parse em segundos. E quando o arquivo for grande ou complexo demais para depurar a olho nu, cole-o no JSON Formatter e deixe que ele faça o trabalho. Se você quer que o JSON seja formatado automaticamente direto na aba do navegador, confira nossa comparação de extensões de JSON formatter para o Chrome.

