Vai al contenuto
jsonbeautifiers
Italiano
V8 Verificato eseguendo il parser su Node v24.15.0, V8 13.6.233.17.

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

Il tuo codice ha chiamato JSON.parse (o res.json()) su un documento HTML. La parentesi angolare in posizione 0 è l’apertura di <!DOCTYPE html>. Il JSON non è malformato; semplicemente non hai ricevuto JSON. Non c’è nulla da sistemare nel parser. È la richiesta a dover essere sistemata.

Potresti vederlo scritto anche così

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

V8 ha riscritto quasi tutti i suoi messaggi di errore JSON nel 2022. La formulazione più vecchia resta quella che mostrano quasi tutti i risultati di ricerca, ma nessun runtime attuale la emette.

Incolla il tuo JSON e vedi esattamente dove si rompe

Input

Nulla di ciò che incolli lascia il tuo browser. L’allowlist connect-src ne fa una garanzia del browser anziché una promessa. Verificalo tu stesso

Che cosa lo provoca davvero

In ordine di quanto spesso ciascuno si rivela essere la risposta.

  1. 01 Il server ha restituito una pagina di errore

    Un 404, un 500 o un errore di gateway reso in HTML. Molti framework restituiscono pagine di errore in HTML anche per le rotte di API, a meno che tu non chieda esplicitamente JSON. Controlla prima il codice di stato, non il corpo.

    Si rompe

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

    Funziona

    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 Una single-page app ha riscritto un percorso sconosciuto verso index.html

    È la causa più comune in sviluppo. Vite, Create React App e quasi tutti i server di sviluppo servono index.html per qualsiasi percorso che non riconoscono, quindi un refuso in una rotta di API o un proxy non configurato restituisce la tua stessa applicazione come HTML con stato 200. Ecco perché controllare res.ok da solo non basta.

  3. 03 La URL si è risolta in un posto inatteso

    Un percorso relativo come fetch("api/user") si risolve rispetto alla rotta corrente, quindi da /settings/profile richiede /settings/api/user. Usa una barra iniziale o una URL assoluta.

    Si rompe

    fetch('api/user')

    Funziona

    fetch('/api/user')
  4. 04 Un captive portal, una VPN o un proxy ha intercettato la richiesta

    Il wifi di un albergo, un proxy aziendale o una challenge anti-bot di Cloudflare restituisce la propria pagina HTML. Si presenta come un errore che colpisce solo alcuni utenti, e solo su certe reti.

  5. 05 PHP ha stampato un warning prima del JSON

    Una notice o un warning emessi prima del corpo della risposta fanno iniziare il documento con <br /> anziché con {. Il JSON è ancora lì, dopo l’HTML. Disattiva display_errors in produzione.

Lo stesso errore in altri runtime

Il problema di fondo è identico; cambia solo la formulazione. Se un collega segnala uno di questi messaggi, sta guardando esattamente la stessa cosa che vedi tu.

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

Domande frequenti

Perché il messaggio è cambiato rispetto a «Unexpected token < in JSON at position 0»?
V8 ha riscritto i suoi messaggi di errore JSON nel 2022 per includere uno spezzone dell’input incriminato. Chrome 104 e successivi, e Node 18 e successivi, stampano la nuova formulazione. La vecchia stringa resta quella che mostrano quasi tutti i risultati di ricerca e le risposte su Stack Overflow, ma nessun runtime attuale la emette.
Il mio JSON è rotto?
No. Non c’è alcun JSON di mezzo. Il parser sta leggendo un documento HTML. Sistema ciò che restituisce la richiesta e l’errore sparisce senza toccare il tuo JSON.
Il codice di stato è 200, allora perché è HTML?
Un server di sviluppo che ripiega su index.html per le rotte sconosciute restituisce 200 con un corpo HTML. Controlla l’header Content-Type oltre allo stato.

Risolvilo adesso

Incolla il payload nello strumento qui sopra, oppure vai direttamente a quello creato per questo compito.

Controlla un payload