HKUDS/DeepTutor · error · MinerUError
MinerU API returned an unexpected (non-JSON) response.
Error message
MinerU API returned an unexpected (non-JSON) response.
What it means
_check_code found the response payload is not a dict: the endpoint returned something that parsed as JSON but wasn't an object (or shape drifted), so the code/msg envelope cannot be inspected.
Solutions
- Log the raw response body to see what was returned.
- Verify api_base_url targets the official v4 API.
- Remove intermediary proxies that transform responses.
Defensive patterns
Strategy: validation
Validate before calling
# post-response sanity check in your own gateway/tests
import json
def is_mineru_payload(text: str) -> bool:
try:
return isinstance(json.loads(text), dict)
except json.JSONDecodeError:
return False Try / catch
except MinerUError as e:
if "non-JSON" in str(e):
log_raw_body(); check_base_url() Prevention
- Point api_base_url only at the official v4 API.
- Avoid response-transforming proxies in front of the API.
When it happens
Trigger: response.json() returning a non-dict — endpoint returning a bare array, an HTML-to-JSON proxy artifact, or an API contract change.
Common situations: Custom api_base_url pointing at an incompatible gateway/proxy that rewrites responses.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- MinerU API did not return an upload URL (missing…
- MinerU reported done but returned no full_zip_url.
- Failed to download MinerU result archive
- Failed to upload PDF to MinerU
- _http_error_message(exc)
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/422202a3d4132dea.
Report an issue: GitHub.
Appendix: source
Thrown at deeptutor/services/parsing/engines/mineru/cloud.py:298
raise MinerUError(f"MinerU API request failed: {exc}") from exc
_check_code(payload)
return payload
raise MinerUError("MinerU API key rotation exhausted.")
def _post_json(client: httpx.Client, path: str, body: dict, key_pool: KeyPool) -> dict:
return _request_json(client.post, path, key_pool, json=body)
def _get_json(client: httpx.Client, path: str, key_pool: KeyPool) -> dict:
return _request_json(client.get, path, key_pool)
def _check_code(payload: dict) -> None:
"""MinerU wraps errors in ``{"code": <non-zero>, "msg": ...}`` even on
HTTP 200, so the business code must be inspected explicitly."""
if not isinstance(payload, dict):
raise MinerUError("MinerU API returned an unexpected (non-JSON) response.")
code = payload.get("code")
if code not in (0, None):
msg = str(payload.get("msg") or "unknown error")
raise MinerUError(f"MinerU API error (code {code}): {msg}")
def _http_error_message(exc: httpx.HTTPStatusError) -> str:
status = exc.response.status_code
if status in (401, 403):
return "MinerU API rejected the token (401/403). Check the API token in Settings → MinerU."
if status == 429:
return "MinerU API rate limit hit (429). Try again later or reduce request volume."
return f"MinerU API returned HTTP {status}."
def _reset_dir(path: Path) -> None:
if path.exists():
import shutilView on GitHub (pinned to 3e82f13042)