Ir para o conteúdo
jsonbeautifiers
Português
V8 Verificado rodando o parser em Node v24.15.0, V8 13.6.233.17.

Unexpected token '<', "<!DOCTYPE "... is not valid JSON

O seu código chamou JSON.parse (ou res.json()) em um documento HTML. O sinal de menor na posição 0 é a abertura de <!DOCTYPE html>. O JSON não está malformado; você simplesmente não recebeu JSON. Não há nada a consertar no parser. A requisição é que precisa de conserto.

Você também pode ver isso escrito assim

  • Unexpected token < in JSON at position 0
  • Unexpected token '<', "<html><hea"... is not valid JSON
  • SyntaxError: Unexpected token < in JSON at position 0

O V8 reescreveu a maior parte das suas mensagens de erro de JSON em 2022. A redação antiga ainda é o que a maioria dos resultados de busca mostra, mas nenhum runtime atual a emite.

Cole o seu JSON e veja exatamente onde ele quebra

Entrada

Nada do que você cola sai do seu navegador. A lista de permissões connect-src transforma isso em uma garantia do navegador, e não em uma promessa. Confira você mesmo

O que realmente causa isso

Ordenados por quantas vezes cada um acaba sendo a resposta.

  1. 01 O servidor devolveu uma página de erro

    Um 404, um 500 ou um erro de gateway renderizado como HTML. Muitos frameworks devolvem páginas de erro em HTML mesmo para rotas de API, a menos que você peça JSON explicitamente. Confira primeiro o código de status, não o corpo.

    Quebra

    const data = await fetch('/api/user').then((r) => r.json());

    Funciona

    const res = await fetch('/api/user', { headers: { Accept: 'application/json' } });
    if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
    const type = res.headers.get('content-type') ?? '';
    if (!type.includes('application/json')) {
      throw new Error(`Expected JSON, got ${type}: ${(await res.text()).slice(0, 200)}`);
    }
    const data = await res.json();
  2. 02 Uma single-page app reescreveu um caminho desconhecido para index.html

    É a causa mais comum em desenvolvimento. Vite, Create React App e a maioria dos servidores de dev servem index.html para qualquer caminho que não reconheçam, então um erro de digitação em uma rota de API ou um proxy mal configurado devolve o seu próprio app como HTML com status 200. É por isso que checar res.ok não basta sozinho.

  3. 03 A URL resolveu para um lugar inesperado

    Um caminho relativo como fetch("api/user") resolve contra a rota atual, então a partir de /settings/profile ele pede /settings/api/user. Use uma barra no começo ou uma URL absoluta.

    Quebra

    fetch('api/user')

    Funciona

    fetch('/api/user')
  4. 04 Um portal cativo, VPN ou proxy interceptou a requisição

    Wi-Fi de hotel, um proxy corporativo ou um desafio anti-bot do Cloudflare devolve a própria página HTML. Isso aparece como um erro que só alguns usuários pegam, e só em algumas redes.

  5. 05 O PHP imprimiu um warning antes do JSON

    Um notice ou warning ecoado antes do corpo da resposta faz o documento começar com <br /> em vez de {. O JSON continua ali, depois do HTML. Desligue display_errors em produção.

O mesmo erro em outros runtimes

O problema de fundo é idêntico; só muda a redação. Se um colega reportar uma dessas mensagens, ele está olhando exatamente para a mesma coisa que você.

Python Expecting value: line 1 column 1 (char 0)
C# (Newtonsoft) Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
C# (System.Text.Json) '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
Java (Jackson) Unexpected character ('<' (code 60)): expected a valid value

Perguntas frequentes

Por que a mensagem mudou de "Unexpected token < in JSON at position 0"?
O V8 reescreveu as mensagens de erro de JSON em 2022 para incluir um trecho da entrada problemática. Chrome 104 em diante e Node 18 em diante imprimem a redação nova. A string antiga ainda é o que a maioria dos resultados de busca e das respostas do Stack Overflow mostra, mas nenhum runtime atual a emite.
O meu JSON está quebrado?
Não. Não há JSON nenhum envolvido. O parser está lendo um documento HTML. Conserte o que a requisição devolve e o erro some sem você tocar no seu JSON.
O status é 200, então por que é HTML?
Um servidor de dev que faz fallback para index.html em rotas desconhecidas devolve 200 com corpo HTML. Confira o cabeçalho Content-Type além do status.

Conserte agora

Cole o payload na ferramenta acima, ou vá direto para a que foi feita para este trabalho.

Conferir um payload