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

The API response body parsed to JSON but is not an object (e.g. a JSON list, string, or null), so the business-code check cannot run.

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 shutil

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Log the raw response body to see what was returned.
  2. Verify api_base_url targets the official v4 API.
  3. 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

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.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/422202a3d4132dea. Report an issue: GitHub.