{"record":{"id":"422202a3d4132dea","repo":"HKUDS/DeepTutor","slug":"mineru-api-returned-an-unexpected-non-json-respo","errorCode":null,"errorMessage":"MinerU API returned an unexpected (non-JSON) response.","messagePattern":"MinerU API returned an unexpected \\(non-JSON\\) response\\.","errorType":"exception","errorClass":"MinerUError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/parsing/engines/mineru/cloud.py","lineNumber":298,"sourceCode":"            raise MinerUError(f\"MinerU API request failed: {exc}\") from exc\n        _check_code(payload)\n        return payload\n    raise MinerUError(\"MinerU API key rotation exhausted.\")\n\n\ndef _post_json(client: httpx.Client, path: str, body: dict, key_pool: KeyPool) -> dict:\n    return _request_json(client.post, path, key_pool, json=body)\n\n\ndef _get_json(client: httpx.Client, path: str, key_pool: KeyPool) -> dict:\n    return _request_json(client.get, path, key_pool)\n\n\ndef _check_code(payload: dict) -> None:\n    \"\"\"MinerU wraps errors in ``{\"code\": <non-zero>, \"msg\": ...}`` even on\n    HTTP 200, so the business code must be inspected explicitly.\"\"\"\n    if not isinstance(payload, dict):\n        raise MinerUError(\"MinerU API returned an unexpected (non-JSON) response.\")\n    code = payload.get(\"code\")\n    if code not in (0, None):\n        msg = str(payload.get(\"msg\") or \"unknown error\")\n        raise MinerUError(f\"MinerU API error (code {code}): {msg}\")\n\n\ndef _http_error_message(exc: httpx.HTTPStatusError) -> str:\n    status = exc.response.status_code\n    if status in (401, 403):\n        return \"MinerU API rejected the token (401/403). Check the API token in Settings → MinerU.\"\n    if status == 429:\n        return \"MinerU API rate limit hit (429). Try again later or reduce request volume.\"\n    return f\"MinerU API returned HTTP {status}.\"\n\n\ndef _reset_dir(path: Path) -> None:\n    if path.exists():\n        import shutil","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/parsing/engines/mineru/cloud.py#L280-L316","documentation":"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.","triggerScenarios":"response.json() returning a non-dict — endpoint returning a bare array, an HTML-to-JSON proxy artifact, or an API contract change.","commonSituations":"Custom api_base_url pointing at an incompatible gateway/proxy that rewrites responses.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# post-response sanity check in your own gateway/tests\nimport json\ndef is_mineru_payload(text: str) -> bool:\n    try:\n        return isinstance(json.loads(text), dict)\n    except json.JSONDecodeError:\n        return False","typeGuard":null,"tryCatchPattern":"except MinerUError as e:\n    if \"non-JSON\" in str(e):\n        log_raw_body(); check_base_url()","preventionTips":["Point api_base_url only at the official v4 API.","Avoid response-transforming proxies in front of the API."],"tags":["mineru","cloud","api-contract","json"],"backgroundTag":"api-unexpected-response-shape","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}