binary-husky/gpt_academic · error · TimeoutError

处理文件 {os.path.basename(fp)} 超时({TIMEOUT_SECONDS}秒)

Error message

处理文件 {os.path.basename(fp)} 超时({TIMEOUT_SECONDS}秒)

What it means

This TimeoutError is the cooperative 30-second per-file budget in BatchDocumentSummarizer. A threading.Timer sets _timeout_occurred on the worker thread; the next check_timeout() call raises with the filename. It marks that one file failed and returns no fragments, but it cannot interrupt code that is already blocked.

Source

Thrown at crazy_functions/Document_Conversation.py:89

                thread._timeout_occurred = True

        # 设置超时标记
        thread = threading.current_thread()
        thread._timeout_occurred = False

        # 设置超时时间为30秒,给予更多处理时间
        TIMEOUT_SECONDS = 30
        timer = threading.Timer(TIMEOUT_SECONDS, timeout_handler)
        timer.start()

        try:
            fp, project_folder = file_info
            fragments = []

            # 定期检查是否超时
            def check_timeout():
                if hasattr(thread, '_timeout_occurred') and thread._timeout_occurred:
                    raise TimeoutError(f"处理文件 {os.path.basename(fp)} 超时({TIMEOUT_SECONDS}秒)")

            # 更新状态
            mutable_status[0] = "检查文件大小"
            mutable_status[1] = time.time()
            check_timeout()

            # 文件大小检查
            if os.path.getsize(fp) > self.max_file_size:
                self.failed_files.append((fp, f"文件过大:超过{self.max_file_size / 1024 / 1024}MB"))
                mutable_status[2] = "文件过大"
                return fragments

            # 更新状态
            mutable_status[0] = "提取文件内容"
            mutable_status[1] = time.time()

            # 提取内容 - 使用单独的超时控制
            content = None

View on GitHub (pinned to d6bde0fa54)

Solutions

  1. Inspect summarizer.failed_files and mutable_status to identify the exact file; remove or process that file separately.
  2. Keep files well below max_file_size and split large documents before upload.
  3. If the workload legitimately needs more time, raise TIMEOUT_SECONDS or make it configurable rather than relying on the hardcoded 30 seconds.
  4. Reduce concurrency so parser subprocesses are not starved on CPU or disk.
  5. Replace the flag-based timer with a real subprocess timeout for extract_text if blocking extraction is the cause.

Example fix

# before
TIMEOUT_SECONDS = 30
timer = threading.Timer(TIMEOUT_SECONDS, timeout_handler)

# after
TIMEOUT_SECONDS = int(os.environ.get("DOC_CONVERSATION_TIMEOUT", "30"))
timer = threading.Timer(TIMEOUT_SECONDS, timeout_handler)
Defensive patterns

Strategy: validation

Validate before calling

from crazy_functions.rag_fns.rag_file_support import supports_format
MAX_SIZE = 10 * 1024 * 1024

def acceptable_document(fp):
    return os.path.isfile(fp) and os.path.getsize(fp) <= MAX_SIZE and os.path.splitext(fp.lower())[1] in supports_format

Type guard

def acceptable_document(fp) -> bool:
    return (
        isinstance(fp, str)
        and os.path.isfile(fp)
        and os.path.getsize(fp) <= 10 * 1024 * 1024
        and os.path.splitext(fp.lower())[1] in {".pdf", ".docx", ".txt", ".md", ".pptx", ".csv", ".epub", ".ipynb"}
    )

Try / catch

try:
    fragments = summarizer._process_single_file_with_timeout(file_info, status)
except TimeoutError as e:
    summarizer.failed_files.append((file_info[0], str(e)))
    fragments = []

Prevention

When it happens

Trigger: A worker passes the size check, extract_text, token splitting, or fragment construction and reaches a checkpoint after the 30-second timer fired. Large or malformed documents, many fragments, slow markitdown/LLamaIndex parsing, or a worker blocked past the deadline all produce it.

Common situations: Uploading a near-10MB PDF or presentation; processing archives containing many files with max_workers up to 32; scanned or complex PDFs; slow disks in Docker; a document whose extraction subprocess hangs until the global timer is already set.

Understand the failure class

Related errors


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