Expecting value: line 1 column 1 (char 0)
Python ti sta dicendo che il primissimo carattere di ciò che gli hai passato non è l’inizio di un valore JSON. In pratica questo non significa quasi mai che il tuo JSON sia malformato in modo sottile. Significa che ciò che hai analizzato non è JSON: una pagina HTML di errore, un corpo vuoto, un messaggio in testo semplice, o niente del tutto. La posizione è riga 1 colonna 1 perché il parser ha fallito prima di leggere alcunché.
Potresti vederlo scritto anche così
- json.decoder.JSONDecodeError: Expecting value
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
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.
-
01 Il corpo della risposta è HTML, non JSON
Una pagina 404, un redirect al login, una challenge di Cloudflare o una pagina di errore di un proxy. La richiesta è riuscita a livello HTTP e ha restituito un documento, solo non quello che ti aspettavi. Stampa le prime centinaia di caratteri prima di analizzare e lo vedrai subito.
Si rompe
r = requests.get(url) data = r.json() # JSONDecodeErrorFunziona
r = requests.get(url) if r.status_code != 200 or 'json' not in r.headers.get('content-type', ''): raise RuntimeError(f"{r.status_code} {r.headers.get('content-type')}: {r.text[:300]}") data = r.json() -
02 Il corpo è vuoto
Un HTTP 204, una richiesta bloccata dal rate limiting che non ha restituito nulla, un WAF che ha scartato il corpo, o un file che esiste ma è di zero byte. Una stringa vuota non è JSON valido. I documenti validi più corti sono null, 0, "", [] e {}.
Si rompe
json.loads("")Funziona
text = r.text if not text.strip(): return None data = json.loads(text) -
03 Stai leggendo un file che non è JSON
Un CSV, un file di log, un pickle Python, oppure un file JSON Lines in cui ogni riga è un documento a sé. Per JSON Lines analizza riga per riga anziché tutto insieme.
Si rompe
with open('events.jsonl') as f: data = json.load(f) # Expecting value, or Extra dataFunziona
with open('events.jsonl') as f: data = [json.loads(line) for line in f if line.strip()] -
04 L’autenticazione è fallita e l’API ha restituito un messaggio in testo semplice
Molte API restituiscono «Unauthorized» o «Forbidden» come testo semplice con un 401 o un 403, non come JSON. Controlla il codice di stato prima di guardare il corpo.
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.
| JavaScript (V8) | Unexpected token '<', "<!DOCTYPE "... is not valid JSON |
|---|---|
| JavaScript (V8), empty input | Unexpected end of JSON input |
| C# (Newtonsoft) | Unexpected character encountered while parsing value: <. Path '', line 0, position 0. |
Domande frequenti
- Perché dice sempre riga 1 colonna 1?
- Perché il parser ha fallito sul primissimo carattere. Non è mai arrivato abbastanza avanti da raggiungere la riga 2. Se il tuo errore indica una riga e una colonna successive, il problema è davvero dentro il tuo JSON ed è un errore diverso.
- Come vedo che cosa ho ricevuto davvero?
- Stampa response.text[:500] prima di chiamare .json(). In nove casi su dieci la risposta si vede già nella prima riga: un <!DOCTYPE html>, una stringa vuota, o un breve messaggio in testo semplice.
- json.loads accetta un oggetto bytes?
- Sì, dalla versione 3.6 di Python json.loads accetta bytes e bytearray oltre a str, e rileva UTF-8, UTF-16 e UTF-32. Quindi questo errore non è causato dal passare dei bytes.
Risolvilo adesso
Incolla il payload nello strumento qui sopra, oppure vai direttamente a quello creato per questo compito.
Valida il tuo JSON