opendatalab/MinerU · error · ValueError
{payload_name} is not valid JSON
Error message
{payload_name} is not valid JSON What it means
ValueError('{payload_name} is not valid JSON') raised by _parse_json_object_response in mineru/cli/router.py when calling response.json() on an httpx response from a (remote or local) mineru worker fails. The HTTP body was not parseable JSON — typically an HTML error page from a proxy, an empty body, a traceback in plain text, or a gateway timeout page. It means the router could not even begin to interpret the worker's reply.
Source
Thrown at mineru/cli/router.py:109
def get_int_env(name: str, default: int, minimum: int = 0) -> int:
try:
value = int(os.getenv(name, str(default)))
except ValueError:
return default
if value < minimum:
return default
return value
def _parse_json_object_response(
response: httpx.Response,
payload_name: str,
) -> dict[str, Any]:
try:
payload = response.json()
except ValueError as exc:
raise ValueError(f"{payload_name} is not valid JSON") from exc
if not isinstance(payload, dict):
raise ValueError(f"{payload_name} must be a JSON object")
return payload
def get_task_retention_seconds() -> int:
return get_int_env(
"MINERU_API_TASK_RETENTION_SECONDS",
DEFAULT_TASK_RETENTION_SECONDS,
minimum=0,
)
def get_task_cleanup_interval_seconds() -> int:
return get_int_env(
"MINERU_API_TASK_CLEANUP_INTERVAL_SECONDS",
DEFAULT_TASK_CLEANUP_INTERVAL_SECONDS,
minimum=1,View on GitHub (pinned to 4fe4bde114)
Solutions
- Inspect the raw body: log response.text (first ~500 chars) to see what was actually returned — the HTML/text usually names the real problem (proxy error, port conflict).
- Verify the worker URL/port: curl the health endpoint directly and confirm it returns JSON.
- Fix proxy behavior: raise proxy timeouts, whitelist the route, or bypass the proxy for worker traffic.
- If the body is empty after a crash, investigate worker logs for OOM/CUDA failures.
Example fix
# before (debugging blind)
payload = _parse_json_object_response(response, 'health payload') # raises bare
# after (diagnose)
try:
payload = _parse_json_object_response(response, 'health payload')
except ValueError:
print(response.status_code, response.headers.get('content-type'))
print(response.text[:500]) # reveals the proxy/HTML error page
raise Defensive patterns
Strategy: try-catch
Validate before calling
def worker_speaks_json(base_url: str) -> bool:
r = requests.get(f'{base_url}/health', timeout=5)
return 'json' in r.headers.get('content-type', '') and r.text.lstrip()[:1] in '{[' Type guard
import json
def looks_like_json_object(text: str) -> bool:
try:
return isinstance(json.loads(text), dict)
except ValueError:
return False Try / catch
try:
payload = _parse_json_object_response(response, 'health payload')
except ValueError as exc:
logger.error('non-JSON worker reply: status=%s ct=%s body=%r',
response.status_code, response.headers.get('content-type'), response.text[:300])
raise Prevention
- Health-check worker URLs with a JSON assertion before adding them to the router pool.
- Keep proxies between router and workers transparent: no HTML error pages, generous timeouts, correct Content-Type.
- Log response bodies on parse failure — the HTML/text content names the offending proxy or crash.
When it happens
Trigger: A reverse proxy (nginx/traefik) in front of the worker returning a 502/504 HTML page; the worker crashing mid-response so the body truncates; hitting a port served by a non-mineru service; auth middleware intercepting with an HTML login page; response gzipped/garbled by a misconfigured proxy.
Common situations: Docker/Kubernetes setups with ingress proxies between router and workers; worker OOM producing partial responses; wrong SERVER_URL/port in the worker list pointing at another HTTP service; TLS termination rewriting bodies.
Related errors
- {payload_name} must be a JSON object
- Timed out waiting for local worker {server_id} to become hea
- Unsupported protocol_version={protocol_version}, expected {A
- max_concurrent_requests must be a positive integer
- MinerU upstream returned an invalid submit payload
AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14).
Data as JSON: /api/errors/37eda44fb5f35dac.
Report an issue: GitHub.