Você está encarando uma stack trace vermelha: SyntaxError: Unexpected token '<', "..." is not valid JSON. Ou talvez seja Unexpected token u in JSON at position 0. De qualquer jeito, JSON.parse() se recusou a rodar e seu código parou. Este guia explica exatamente o que cada variante desse erro significa, por que acontece, e como consertar —— rápido.
Como o erro aparece de verdade
A redação varia por engine JavaScript, mas todas significam a mesma coisa: o parser bateu num caractere que não esperava numa posição específica da sua string.
// V8 (Chrome, Node.js, Edge)
SyntaxError: Unexpected token '<', "<html>..." is not valid JSON
SyntaxError: Unexpected token 'u', "undefined" is not valid JSON
SyntaxError: Unexpected token u in JSON at position 0 // V8 mais antigo
SyntaxError: Expected ',' or '}' after property value in JSON at position 42
// Firefox (SpiderMonkey)
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data
// Safari (JavaScriptCore)
SyntaxError: JSON Parse error: Unexpected identifier "undefined"
SyntaxError: JSON Parse error: Single quotes (') are not allowed in JSONA informação chave está sempre em duas partes: que caractere foi inesperado e onde. O caractere te diz o que o parser efetivamente recebeu; a posição te diz onde olhar na string.
Causa 1: o servidor devolveu HTML em vez de JSON
Essa é a causa mais comum de Unexpected token '<'. Seu fetch ou chamada AJAX recebeu uma página HTML —— normalmente uma 404, um redirect de login, ou um erro de servidor —— em vez do JSON esperado. O < é a abertura de <!DOCTYPE html> ou <html>.
// ❌ Isso quebra com "Unexpected token '<'"
const res = await fetch('/api/user');
const data = await res.json(); // servidor devolveu HTML 404
// ✅ Cheque o status da resposta primeiro
const res = await fetch('/api/user');
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const data = await res.json(); Sempre cheque res.ok (ou res.status) antes de chamar res.json(). Você também pode inspecionar o texto cru da resposta primeiro:
const text = await res.text();
console.log(text.slice(0, 200)); // veja o que de fato veio
const data = JSON.parse(text);Causa 2: o valor é undefined
Unexpected token 'u' na posição 0 quase sempre significa que você chamou JSON.parse(undefined). A string "undefined" começa com a letra u, que não é um caractere de início válido de JSON.
// ❌ variável nunca foi setada
const raw = localStorage.getItem('settings'); // devolve null se ausente
JSON.parse(raw); // null tudo bem, mas se raw for undefined por algum motivo...
// ❌ dado async ainda não carregado
JSON.parse(this.state.data); // data é undefined no primeiro render
// ✅ Guard antes de parsear
if (raw) {
const data = JSON.parse(raw);
} Note que localStorage.getItem() devolve null (não undefined) para keys ausentes, e JSON.parse(null) devolve null sem erro. Os suspeitos comuns são variáveis de state não inicializadas ou um argumento de função ausente.
Causa 3: aspas simples em vez de duplas
// ❌ SyntaxError: Unexpected token '''
JSON.parse("{'name': 'Ada'}");
// ✅ JSON requer aspas duplas
JSON.parse('{"name": "Ada"}')Literais de objeto JavaScript aceitam aspas simples. JSON não —— todas as strings, incluindo as keys, têm que usar aspas duplas. Isso costuma acontecer quando alguém serializa dado com a função str() do Python em vez de json.dumps(), ou copia um literal de objeto direto.
Causa 4: vírgula no final
// ❌ SyntaxError: Unexpected token '}'
JSON.parse('{"name": "Ada", "score": 98,}');
// ^ vírgula no final
// ✅
JSON.parse('{"name": "Ada", "score": 98}')JavaScript moderno permite vírgulas no final em arrays e objetos. JSON não. Arquivos de configuração JSON editados à mão são a fonte mais comum desse erro.
Causa 5: keys sem aspas
// ❌ SyntaxError: Unexpected token 'n'
JSON.parse("{name: 'Ada'}");
// ✅
JSON.parse('{"name": "Ada"}') As keys de objeto em JSON precisam sempre ser strings entre aspas duplas. Identificadores nus tipo name são válidos em literais de objeto JavaScript mas não em JSON.
Causa 6: comentários no JSON
// ❌ SyntaxError: Unexpected token '/'
JSON.parse(`{
// registro do usuário
"name": "Ada"
}`);
// ✅ Tire os comentários antes de parsear (ou use um parser JSONC)
const stripped = raw.replace(///.*$/gm, '').replace(//*[sS]*?*//g, '');
JSON.parse(stripped);JSON não tem sintaxe de comentários. Comentários são frequentemente adicionados a arquivos de configuração (o formato JSONC), mas o JSON.parse() padrão rejeita na hora.
Causa 7: um BOM ou caractere invisível na posição 0
Se o erro diz posição 0 mas o primeiro caractere visível parece tranquilo, pode ter um byte-order mark invisível (BOM, U+FEFF) ou outro caractere de controle no início da string —— tipicamente ao ler um arquivo salvo com codificação UTF-8-BOM no Windows.
// ✅ Tire o BOM antes de parsear
const clean = raw.replace(/^/, '');
JSON.parse(clean);Causa 8: tokens I ou N —— Infinity e NaN
Se o erro diz Unexpected token I ou Unexpected token N, a fonte produziu Infinity, -Infinity, ou NaN —— todos válidos em JavaScript mas não em JSON.
// ❌ Erro do lado produtor
const json = '{"ratio": NaN, "limit": Infinity}';
JSON.parse(json); // Unexpected token N (or I) ...
// ✅ Codifique deliberadamente
const safe = JSON.stringify({ ratio: NaN, limit: Infinity });
// → '{"ratio":null,"limit":null}' (nota: com perda —— ambos viram null)
// ✅ Sem perda: codifique como uma string sentinela que você parseia de volta
JSON.stringify({ ratio: 'NaN', limit: 'Infinity' });JSON.stringify converte silenciosamente NaN / Infinity para null. Se você precisa que façam round-trip, substitua por uma string sentinela na saída e parseie de volta na entrada.
Como achar a posição exata do erro
A mensagem de erro inclui um número de posição. Use ele pra fatiar a string e ver exatamente o que tem ali:
function parseWithContext(text) {
try {
return JSON.parse(text);
} catch (err) {
// Extrai a posição da mensagem de erro do V8
const match = err.message.match(/position (\d+)/);
if (match) {
const pos = Number(match[1]);
const snippet = text.slice(Math.max(0, pos - 20), pos + 20);
console.error(`Error near: ..."${snippet}"...`);
console.error(` ${''.padStart(Math.min(pos, 20), ' ')}^`);
}
throw err;
}
}Perguntas frequentes
O que significa «Unexpected token in JSON»?
Significa que JSON.parse() bateu num caractere que não é válido naquele ponto da gramática. O token nomeado te diz o que foi recebido (< = HTML, u = undefined, ' = aspas simples) e a posição te diz onde olhar.
Por que «Unexpected token '<'» acontece com fetch?
Sua requisição devolveu uma página HTML —— um 404, um redirect de login, ou erro de servidor —— em vez de JSON, e o < é a tag HTML de abertura. Cheque response.ok antes de chamar response.json() e logue await response.text() pra ver o que de fato voltou.
Como consertar «Unexpected token u in JSON at position 0»?
Você passou undefined para JSON.parse(). Coloque um guard no valor antes (if (raw) JSON.parse(raw)) e cheque state não inicializado ou argumento de função ausente. A variante intimamente relacionada token o é tratada em Unexpected token o in JSON.
Como acho a posição exata do erro?
Leia o número de posição na mensagem de erro e fatie a string em volta (veja o snippet acima), ou cole o JSON no JSON Fix, que destaca a linha exata do problema.
O conserto mais rápido: cole e repare online
Se você tem uma string JSON quebrada e só quer que ela seja consertada agora, o JSON Fix lida com todas as causas acima automaticamente —— aspas simples, vírgulas no final, keys sem aspas, comentários, literais Python e mais. Cole seu JSON, clique Repair & Format, e tenha JSON válido e limpo de volta num passo. Tudo roda no seu navegador; nada é enviado pra qualquer servidor.
- JSON Fix —— auto-conserta JSON quebrado e mostra a linha exata do erro
- Consertar erros JSON Unexpected Token —— referência rápida pra cada variante de unexpected token
- Consertar «[object Object] is Not Valid JSON» —— o erro relacionado quando um objeto é forçado a string antes de parsear
- JSON Diff —— compare um JSON antes/depois para verificar que seu conserto não mudou nada inesperado