🌐 Detecting your location…

Como corrigir token inesperado SyntaxError em JSON na posição 0

⏱️5 min read  ·  1,091 words

O erroSyntaxError: Token inesperado ‘<‘ , “<!DOCTYPE”… não é JSON válido (ou “Token inesperado em JSON na posição 0”) significa que você tentou analisar algo que não é JSON — geralmente uma página de erro HTML ou uma resposta vazia. Veja como diagnosticar e corrigir isso.

O que esse erro significa

Você ligouJSON.parse() or response.json() em uma resposta que não é JSON válida. As pistas “posição 0” e “<” são fundamentais: posição 0 significa que o primeiro caractere está errado e “<” significa que a resposta começa com HTML (como<!DOCTYPE html>) — você obteve uma página de erro HTML em vez de JSON.

Causa 1: o servidor retornou uma página de erro HTML

// 🐛 The API returned a 404/500 HTML page, not JSON
const response = await fetch('/api/data');
const data = await response.json();   // ❌ fails - response is HTML

// The response body is something like:
// 
404 Not Found...
// JSON.parse chokes on the '<' at position 0

// ✅ Check the response status and content type first
const response = await fetch('/api/data');
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const contentType = response.headers.get('content-type');
if (!contentType?.includes('application/json')) {
  const text = await response.text();
  throw new Error(`Expected JSON but got: ${text.slice(0, 100)}`);
}
const data = await response.json();

Causa 2: Corpo de resposta vazio

// 🐛 Parsing an empty response (e.g., 204 No Content)
const data = await response.json();   // ❌ fails if body is empty

// ✅ Handle empty bodies
const text = await response.text();
const data = text ? JSON.parse(text) : null;

// ✅ Or check status
if (response.status === 204) {
  return null;   // No Content - nothing to parse
}
const data = await response.json();

Causa 3: URL / endpoint de API errado

// 🐛 Wrong URL returns your app's HTML (SPA fallback) instead of API JSON
fetch('/api/users')     // typo or wrong path
// If /api/users doesn't exist, the server may return index.html
// (common with SPAs) - which starts with '<' -> parse error

// ✅ Verify the URL is correct and the endpoint exists
// Check the Network tab to see what the response actually is
// Ensure API routes are registered and the path is exact

Causa 4: JSON já analisado com análise dupla

// 🐛 The data is already an object, but you parse it again
const data = await response.json();   // already parsed to an object
const parsed = JSON.parse(data);      // ❌ parsing an object fails

// ✅ response.json() already parses - don't parse again
const data = await response.json();   // done - it's an object

// axios also auto-parses:
const { data } = await axios.get('/api');   // data is already parsed

Causa 5: caracteres finais ou JSON inválido

// 🐛 The JSON has a syntax error (trailing comma, single quotes)
JSON.parse('{"name": "Alice",}');       // ❌ trailing comma
JSON.parse("{'name': 'Alice'}");        // ❌ single quotes not valid JSON
JSON.parse('{name: "Alice"}');          // ❌ unquoted key

// ✅ Valid JSON requires double quotes, no trailing commas
JSON.parse('{"name": "Alice"}');        // ✓ valid

O padrão de busca robusto

async function fetchJSON(url, options) {
  const response = await fetch(url, options);

  // Check status
  if (!response.ok) {
    const text = await response.text();
    throw new Error(`HTTP ${response.status}: ${text.slice(0, 200)}`);
  }

  // Handle empty responses
  const text = await response.text();
  if (!text) return null;

  // Parse safely with a helpful error
  try {
    return JSON.parse(text);
  } catch (err) {
    throw new Error(`Invalid JSON response: ${text.slice(0, 200)}`);
  }
}

// Usage
try {
  const data = await fetchJSON('/api/users');
} catch (err) {
  console.error('Fetch failed:', err.message);   // clear error, not cryptic
}

Etapas de depuração

// 1. Log the raw response text to see what you actually got
const response = await fetch(url);
const text = await response.text();
console.log('Raw response:', text);   // reveals HTML, empty, or malformed JSON

// 2. Check the Network tab in DevTools
//    - Status code (200? 404? 500?)
//    - Content-Type header (application/json?)
//    - Response body (is it actually JSON?)

// 3. Test the endpoint directly
curl -i https://api.example.com/data
// See the exact status, headers, and body

Perguntas Frequentes

P: Por que o erro menciona “<” ou “<!DOCTYPE”?
R: Porque a resposta começa com HTML, não com JSON. Você obteve uma página HTML (geralmente uma página de erro 404 ou 500, ou index.html do seu SPA) em vez do JSON esperado. O “<” é o primeiro caractere da tag HTML, que não é JSON válido.

P: Por que funciona algumas vezes, mas outras não?
R: Ele falha quando o servidor retorna não-JSON — uma página de erro (404/500), um corpo vazio ou um redirecionamento para HTML. Funciona quando a API retorna JSON adequado. A falha intermitente geralmente significa que a API às vezes apresenta erros e retorna páginas de erro HTML.

P: Como evito esse erro?
R: Sempre verifiqueresponse.ok e o tipo de conteúdo antes de chamarresponse.json(), manipule corpos vazios e envolva a análise em try/catch. Use um wrapper de busca robusto (mostrado acima) que forneça erros claros em vez da mensagem enigmática de “token inesperado”.

P: Estou recebendo o HTML do meu aplicativo em vez dos dados da API. Por que?
R: Provavelmente o URL da sua API está errado ou o endpoint não existe, então o servidor volta a servir o index.html do seu SPA (que começa com <!DOCTYPE). Verifique se o caminho da API está correto e se o endpoint está registrado. Verifique a guia Rede para ver a resposta real.

P: Devo usar response.json() ou response.text() e depois JSON.parse()?
A: response.json() é conveniente, mas gera um erro enigmático em JSON inválido. Usandoresponse.text() entãoJSON.parse() em um try/catch permite inspecionar a resposta bruta e fornecer uma mensagem de erro clara quando não for JSON – melhor para depuração.

Conclusão

“SyntaxError: Token inesperado em JSON na posição 0” significa que você tentou analisar não JSON – quase sempre uma página de erro HTML (começa com “<“) ou uma resposta vazia. A correção:verificarresponse.ok e o cabeçalho do tipo de conteúdo antes de analisar, manipule corpos vazios e envolva JSON.parse em try/catch. A pista “<” informa que a resposta é HTML, então investigue o motivo – geralmente um URL errado, um erro do servidor retornando uma página de erro HTML ou um substituto de SPA. Use um wrapper de busca robusto que registre a resposta bruta e forneça erros claros. Depois de verificar a resposta antes de analisá-la, esse erro enigmático se torna informativo e aponta diretamente para o problema real.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা