binary-husky/gpt_academic · error · RuntimeError

Doc2x conversion timeout after maximum attempts

Error message

Doc2x conversion timeout after maximum attempts

What it means

The second polling loop (step 4, convert-status) gives up when the convert job still reports 'processing' after max_attempts polls at 3-second intervals. Note the asymmetry with error 77: unlike the parse loop, the 'else' branch is absent here — an unexpected status silently falls through and can loop until this timeout instead of raising error 76's counterpart.

Source

Thrown at crazy_functions/pdf_fns/parse_pdf_via_doc2x.py:170

    max_attempts = 36
    attempt = 0
    while attempt < max_attempts:
        res = make_request(
            "GET",
            "https://v2.doc2x.noedgeai.com/api/v2/convert/parse/result",
            headers={"Authorization": "Bearer " + doc2x_api_key},
            params=params,
            timeout=15,
        )
        res_data = doc2x_api_response_status(res, uid=f"uid: {uuid}")
        if res_data["status"] == "success":
            break
        elif res_data["status"] == "processing":
            time.sleep(3)
            logger.info("Doc2x still processing to convert file")
            attempt += 1
    if attempt >= max_attempts:
        raise RuntimeError("Doc2x conversion timeout after maximum attempts")

    # < ------ 第5步:最后的处理 ------ >
    logger.info("Doc2x 第5步:下载转换后的文件")

    if format == "tex":
        target_path = latex_dir
    if format == "md":
        target_path = markdown_dir
    os.makedirs(target_path, exist_ok=True)

    max_attempt = 3
    # < ------ 下载 ------ >
    for attempt in range(max_attempt):
        try:
            result_url = res_data["url"]
            res = make_request("GET", result_url, timeout=60)
            zip_path = os.path.join(target_path, gen_time_str() + ".zip")
            unzip_path = os.path.join(target_path, gen_time_str())

View on GitHub (pinned to d6bde0fa54)

Solutions

  1. Raise max_attempts for the convert loop (it is a separate budget from the parse loop)
  2. Retry the conversion — if the parse succeeded, reusing the uid usually resumes quickly
  3. Reduce output size: convert to 'md' instead of 'tex' if formulas are not needed
  4. Add an explicit else-branch raising on unknown statuses so real failures surface immediately instead of as this timeout

Example fix

# before
if res_data["status"] == "success":
    break
elif res_data["status"] == "processing":
    time.sleep(3); attempt += 1

# after
if res_data["status"] == "success":
    break
elif res_data["status"] == "processing":
    time.sleep(3); attempt += 1
else:
    raise RuntimeError(f"Doc2x convert failed: {res_data}")
Defensive patterns

Strategy: retry

Validate before calling

if res_data['status'] not in ('success', 'processing'):
    raise RuntimeError(f"Unexpected convert status: {res_data['status']}")  # fail fast, do not burn attempts

Try / catch

try:
    wait_for_conversion(uuid)
except RuntimeError as e:
    if 'conversion timeout' in str(e):
        time.sleep(30)
        wait_for_conversion(uuid, max_attempts=60)
    else:
        raise

Prevention

When it happens

Trigger: Converting a large parsed document to tex/md takes longer than max_attempts × 3s; Doc2x conversion queue backlog; very formula-dense documents converting slowly.

Common situations: Same shape as 77 but at the convert stage; large documents, server load; also triggered when an unhandled failure status causes the loop to exhaust attempts without a clear error.

Understand the failure class

Related errors


AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14). Data as JSON: /api/errors/993e60ce34d17c4c. Report an issue: GitHub.