{"record":{"id":"29861d59ad1efd92","repo":"binary-husky/gpt_academic","slug":"doc2x-return-an-error-res-data","errorCode":null,"errorMessage":"Doc2x return an error: {res_data}","messagePattern":"Doc2x return an error: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"crazy_functions/pdf_fns/parse_pdf_via_doc2x.py","lineNumber":128,"sourceCode":"    max_attempts = 60\n    attempt = 0\n    while attempt < max_attempts:\n        res = make_request(\n            \"GET\",\n            \"https://v2.doc2x.noedgeai.com/api/v2/parse/status\",\n            headers={\"Authorization\": \"Bearer \" + doc2x_api_key},\n            params=params,\n            timeout=15,\n        )\n        res_data = doc2x_api_response_status(res)\n        if res_data[\"status\"] == \"success\":\n            break\n        elif res_data[\"status\"] == \"processing\":\n            time.sleep(5)\n            logger.info(f\"Doc2x is processing at {res_data['progress']}%\")\n            attempt += 1\n        else:\n            raise RuntimeError(f\"Doc2x return an error: {res_data}\")\n    if attempt >= max_attempts:\n        raise RuntimeError(\"Doc2x processing timeout after maximum attempts\")\n\n    # < ------ 第3步：提交转化 ------ >\n    logger.info(\"Doc2x 第3步：提交转化\")\n    data = {\n        \"uid\": uuid,\n        \"to\": format,\n        \"formula_mode\": \"dollar\",\n        \"filename\": \"output\"\n    }\n    res = make_request(\n        \"POST\",\n        \"https://v2.doc2x.noedgeai.com/api/v2/convert/parse\",\n        headers={\"Authorization\": \"Bearer \" + doc2x_api_key},\n        json=data,\n        timeout=15,\n    )","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/crazy_functions/pdf_fns/parse_pdf_via_doc2x.py#L110-L146","documentation":"During the parse-status polling loop, the response passed status validation but its data.status field is neither 'success' nor 'processing' — an unexpected terminal state (e.g. 'failed' or 'error'). The whole data dict is embedded in the message, which will be large but shows the failure reason from Doc2x.","triggerScenarios":"Doc2x fails to parse the uploaded PDF server-side (data.status == 'failed'); API adds a new status value the client does not handle; the parse job is cancelled server-side.","commonSituations":"Scanned or complex PDFs that Doc2x's engine rejects mid-processing; very large files timing out server-side; intermittent service degradation.","solutions":["Inspect res_data in the message — it typically contains a 'msg'/'message' explaining the server-side failure","Retry once: transient server-side parse failures are common; if it fails identically, the PDF is the problem","Test the same PDF with a smaller/simpler document to isolate content-specific failures","For scanned PDFs, OCR first, or switch to the GROBID-based parsing plugin instead of Doc2x"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"def parse_status_ok(res_data: dict) -> bool:\n    return res_data.get('status') in ('success', 'processing')","typeGuard":null,"tryCatchPattern":"try:\n    poll_parse_status(uuid)\nexcept RuntimeError as e:\n    if 'Doc2x return an error' in str(e) and 'failed' in str(e).lower():\n        raise RuntimeError('Doc2x could not parse this PDF (server-side); try another parser') from e\n    raise","preventionTips":["Treat unknown data.status values as terminal failures immediately with full payload logging","Retry once — transient server-side failures do occur; identical second failure means bad input","Keep the GROBID plugin as an alternate parsing path for rejected files"],"tags":["doc2x","api","polling","parse-failure"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}