Back

Corrigindo 'Unexpected token < in JSON at position 0'

Corrigindo 'Unexpected token < in JSON at position 0'

Você chama response.json() e sua aplicação trava com SyntaxError: Unexpected token '<' in JSON at position 0. O caractere < revela exatamente o que aconteceu: seu código esperava JSON, mas recebeu HTML.

Este erro de análise de JSON aparece constantemente em stacks frontend modernos—browser fetch, Node.js, rotas de API do Next.js e funções serverless. Entender por que isso acontece e como depurá-lo rapidamente vai economizar horas de frustração.

Pontos-Chave

  • O erro “Unexpected token <” significa que você está analisando HTML como JSON—o < geralmente vem de <!DOCTYPE html> ou de uma tag HTML.
  • Causas comuns incluem URLs incorretas, redirecionamentos de autenticação, erros de servidor retornando páginas HTML e cabeçalhos Content-Type ausentes.
  • Depure verificando primeiro o código de status HTTP, depois o cabeçalho Content-Type e, em seguida, o corpo bruto da resposta usando response.text().
  • Construa wrappers defensivos de fetch que validem as respostas antes de analisá-las para capturar esses problemas com mensagens de erro claras.

Por Que Sua API Retorna HTML em Vez de JSON

O erro significa que JSON.parse() encontrou um documento HTML onde esperava JSON válido. O < na posição 0 é tipicamente o caractere de abertura de <!DOCTYPE html> ou de uma tag HTML.

Vários cenários causam essa incompatibilidade de Content-Type:

URLs de endpoint incorretas ou com erros de digitação. Um erro de digitação na URL do seu fetch retorna uma página 404—que é HTML, não JSON.

Redirecionamentos de autenticação. Tokens expirados ou cabeçalhos de autenticação ausentes acionam redirecionamentos para páginas de login. Seu fetch recebe o HTML da página de login.

Erros de servidor retornando páginas HTML de erro. Um erro 500 do seu API gateway ou provedor de nuvem frequentemente retorna uma página HTML de erro estilizada em vez de uma resposta JSON de erro.

Servidores de desenvolvimento servindo HTML de fallback para rotas desconhecidas. Muitas SPAs retornam o shell HTML para caminhos não correspondentes, embora alguns servidores de desenvolvimento modernos retornem payloads de erro estruturados.

Cabeçalhos Content-Type ausentes ou incorretos. Código de servidor que esquece de definir Content-Type: application/json pode ter HTML como padrão.

Um Fluxo Prático de Depuração para Erros de Fetch API

Quando a análise de JSON falha, siga esta sequência para identificar a causa raiz:

Passo 1: Verifique o Código de Status HTTP

Antes de analisar, verifique o status da resposta. Um status 4xx ou 5xx frequentemente indica que a resposta não será JSON:

const response = await fetch('/api/data')

if (!response.ok) {
  console.error(`HTTP ${response.status}: ${response.statusText}`)
  const text = await response.text()
  console.error('Response body:', text.substring(0, 200))
  throw new Error(`Request failed with status ${response.status}`)
}

Passo 2: Valide o Cabeçalho Content-Type

Verifique o que o servidor afirma estar enviando:

const contentType = response.headers.get('content-type')

if (!contentType || !contentType.includes('application/json')) {
  const text = await response.text()
  throw new Error(`Expected JSON, received: ${contentType}. Body: ${text.substring(0, 100)}`)
}

const data = await response.json()

Passo 3: Registre o Corpo Bruto da Resposta

Quando a análise falha, use response.text() em vez de response.json() para ver o que você realmente recebeu:

async function fetchWithDebug(url) {
  const response = await fetch(url)
  const text = await response.text()
  
  try {
    return JSON.parse(text)
  } catch (error) {
    console.error('Failed to parse JSON. Raw response:', text.substring(0, 500))
    throw error
  }
}

Armadilhas Comuns do Mundo Real

URLs base de API incorretas em produção. Variáveis de ambiente apontando para domínios errados ou barras finais ausentes causam 404s que retornam HTML.

API gateways e CDNs interceptando requisições. Serviços como Cloudflare, AWS API Gateway ou Vercel podem retornar suas próprias páginas HTML de erro para limites de taxa, timeouts ou configurações incorretas.

App Router do Next.js e redirecionamentos de middleware. Middleware ou redirecionamentos de autenticação frequentemente retornam HTML, embora alguns caminhos de redirecionamento emitam pequenos payloads JSON.

Código de servidor sem cabeçalhos JSON. Seu handler de API retorna dados, mas esquece de definir o tipo de conteúdo da resposta:

// ❌ Content-Type ausente
res.send({ data: 'value' })

// ✅ Resposta JSON explícita
res.json({ data: 'value' })

Problemas de CORS. Navegadores bloqueiam requisições preflight com falha antes do seu código executar, mas servidores ou proxies mal configurados ainda podem retornar uma página HTML de erro que sua chamada fetch recebe.

Padrão Defensivo de Fetch

Encapsule suas chamadas fetch com validação para capturar esses problemas antecipadamente:

async function safeFetch(url, options = {}) {
  const response = await fetch(url, options)
  
  if (!response.ok) {
    const body = await response.text()
    throw new Error(`HTTP ${response.status}: ${body.substring(0, 100)}`)
  }
  
  const contentType = response.headers.get('content-type')
  if (!contentType?.includes('application/json')) {
    const body = await response.text()
    throw new Error(`Invalid content-type: ${contentType}`)
  }
  
  return response.json()
}

Conclusão

O erro “Unexpected token <” sempre significa que você está analisando HTML como JSON. Depure verificando primeiro o código de status, depois o cabeçalho Content-Type e, em seguida, o corpo bruto da resposta. A maioria dos casos remonta a URLs incorretas, redirecionamentos de autenticação ou erros de servidor retornando páginas HTML. Construa wrappers defensivos de fetch que validem as respostas antes de analisá-las para capturar esses problemas com mensagens de erro claras.

Perguntas Frequentes

Ambientes de produção frequentemente têm configurações diferentes. Verifique se a variável de ambiente da URL base da sua API está definida corretamente, confirme se seus tokens de autenticação são válidos e certifique-se de que quaisquer proxies ou CDNs entre seu frontend e API estejam configurados adequadamente. Servidores de produção também podem ter políticas CORS mais rigorosas que causam falhas nas requisições.

Sim. Encapsule suas chamadas fetch em uma função defensiva que verifica o status da resposta e o cabeçalho Content-Type antes de chamar response.json(). Isso permite que você trate o erro graciosamente e exiba uma mensagem significativa aos usuários em vez de travar. Sempre valide as respostas antes de analisá-las.

Use a aba Network do seu navegador para inspecionar a resposta real. Se a resposta mostrar conteúdo HTML com status 404 ou 500, o servidor está retornando uma página de erro. Se o status for 200 mas o conteúdo for HTML, verifique seu código de servidor para garantir que ele define o cabeçalho Content-Type correto e retorna JSON.

O método response.json() tenta analisar o corpo da resposta como JSON. Se o corpo contém HTML ou qualquer conteúdo não-JSON, a análise falha. O método response.text() simplesmente retorna a resposta bruta como uma string sem análise, por isso funciona independentemente do tipo de conteúdo. Use text() para depuração para ver o que você realmente recebeu.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay