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
- Retries are built in (3 attempts) — persistent failure means the URL expired; re-run the whole flow to get a fresh URL
- Reduce delay between convert-success and download so the presigned URL does not expire
- If res.json() raised, capture res.text instead for non-JSON error bodies
- 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
- Download immediately after convert-success so the presigned URL cannot expire
- Read res.text, not res.json(), on non-200 bodies
- If built-in 3 retries fail, restart from upload — a fresh URL is the only cure for expiry
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
- Doc2x return an error: Trace ID: {trace_id} {uid} {response.
- 无法下载论文 {self.doi},所有重试都失败了
- 无法下载资源{txt},请检查。
- Failed to download webpage after {self.config.max_retries} a
- 解析PDF失败,请检查PDF是否损坏。
AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14).
Data as JSON: /api/errors/22d0d0ea6bd8741b.
Report an issue: GitHub.