binary-husky/gpt_academic · error · RuntimeError

Doc2x return an error: {res.json()}

Error message

Doc2x return an error: {res.json()}

What it means

During file download (step 5), the GET to the result URL returned a non-200 status, so the client raises with res.json() embedded. The surrounding loop retries up to 3 times with a 3s backoff, re-raising the last error only after all attempts fail. Non-200 on a presigned result URL typically means the URL expired or the download service is flaky.

Source

Thrown at crazy_functions/pdf_fns/parse_pdf_via_doc2x.py:193

    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())
            if res.status_code == 200:
                with open(zip_path, "wb") as f:
                    f.write(res.content)
            else:
                raise RuntimeError(f"Doc2x return an error: {res.json()}")
        except Exception as e:
            if attempt < max_attempt - 1:
                logger.error(f"Failed to download uid = {uuid} file, retrying... {e}")
                time.sleep(3)
                continue
            else:
                raise e

    # < ------ 解压 ------ >
    import zipfile
    with zipfile.ZipFile(zip_path, "r") as zip_ref:
        zip_ref.extractall(unzip_path)
    return zip_path, unzip_path


def 解析PDF_DOC2X_单文件(
    fp,
    project_folder,

View on GitHub (pinned to d6bde0fa54)

Solutions

  1. Retries are built in (3 attempts) — persistent failure means the URL expired; re-run the whole flow to get a fresh URL
  2. Reduce delay between convert-success and download so the presigned URL does not expire
  3. If res.json() raised, capture res.text instead for non-JSON error bodies
  4. Check network/proxy egress to the download host

Example fix

# before
raise RuntimeError(f"Doc2x return an error: {res.json()}")

# after
raise RuntimeError(f"Doc2x download error {res.status_code}: {res.text[:500]}")
Defensive patterns

Strategy: retry

Validate before calling

if res.status_code != 200:
    # do not blindly res.json() — error bodies may not be JSON
    raise RuntimeError(f"download {res.status_code}: {res.text[:200]}")

Try / catch

for attempt in range(3):
    try:
        download_result(url)
        break
    except RuntimeError as e:
        if attempt == 2 or 'expired' in str(e).lower():
            restart_full_doc2x_flow(pdf_path)  # expired presigned URL needs a fresh one
        time.sleep(3)

Prevention

When it happens

Trigger: Presigned download URL expired because polling took too long (see 77/78); transient CDN/origin 5xx; res.json() itself raising if the error body is not JSON (which would surface as a JSONDecodeError instead of this message); network proxy mangling the request.

Common situations: See trigger scenarios.

Related errors


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