JSONDecodeError: Expecting value: line 1 column 1
Esse erro engana porque parece problema de formato. Quase sempre ele significa outra coisa: a resposta veio vazia, ou veio uma página de erro em HTML, e o seu código tentou ler aquilo como se fosse JSON.
O que “line 1 column 1 (char 0)” quer dizer
Que o interpretador olhou o primeiro caractere da resposta e ele já não era JSON. Ou seja: não é JSON malformado no meio — é JSON nenhum. Os culpados de sempre:
- Resposta vazia — a conexão caiu ou expirou;
- Página HTML de erro — 502, 503, manutenção, tela de
proteção contra robôs. Começa com
<!DOCTYPE html>; - Bloqueio por excesso de requisições (429) — costuma vir em HTML ou texto puro;
- Endpoint mudou e agora devolve redirecionamento.
Como resolver
Olhe a resposta antes de interpretar
Trinta segundos de diagnóstico resolvem o que horas de palpite não resolvem:
print(resp.status_code)
print(resp.text[:400]) # os primeiros 400 caracteres bastam
Se aparecer <html>, o problema é do lado do servidor ou de
bloqueio — não do seu parser.
Falhe com informação, não com o erro cru
import json
try:
dados = resp.json()
except json.JSONDecodeError:
raise RuntimeError(
f'Resposta não-JSON (HTTP {resp.status_code}): {resp.text[:200]!r}'
)
Assim o log do dia seguinte diz o que aconteceu, em vez de repetir a mesma linha misteriosa.
Repita só o que faz sentido repetir
Erro 5xx e resposta vazia valem nova tentativa, com espera crescente. Já 401, 403 e 404 não vão melhorar sozinhos — repetir só aumenta a chance de a corretora limitar você.
Confira se o problema não é a conexão morta
Se isso começa depois de horas rodando, provavelmente é a mesma raiz de “Connection is already closed”: a sessão caiu e as respostas viraram vazio.
Antes de deixar o robó operar
Consertar o erro faz o robô rodar — não faz ele ganhar. O Binaryzando testa a sua estratégia no histórico real de velas antes de você arriscar dinheiro nela, e sela o resultado numa carta com código verificável — para o número não poder ser editado depois.
Testar minha estratégia