infiniflow/ragflow · error · TimeoutError

Function '{func.__name__}' timed out after {seconds} seconds

Error message

Function '{func.__name__}' timed out after {seconds} seconds and {attempts} attempts.

What it means

TimeoutError raised by the sync branch of the @timeout decorator in common/connection_utils.py:36-61. The decorator runs the wrapped function in a daemon thread and collects its result via a queue; with ENABLE_TIMEOUT_ASSERTION set, each of `attempts` tries waits up to `seconds` for the result, and if the queue never yields one, the wrapper raises this TimeoutError naming the function, seconds, and attempts. Without ENABLE_TIMEOUT_ASSERTION the sync path blocks indefinitely and this error cannot fire.

Source

Thrown at common/connection_utils.py:61

                except Exception as e:
                    result_queue.put(e)

            thread = threading.Thread(target=target)
            thread.daemon = True
            thread.start()

            for a in range(attempts):
                try:
                    if os.environ.get("ENABLE_TIMEOUT_ASSERTION"):
                        result = result_queue.get(timeout=seconds)
                    else:
                        result = result_queue.get()
                    if isinstance(result, Exception):
                        raise result
                    return result
                except queue.Empty:
                    pass
            raise TimeoutError(f"Function '{func.__name__}' timed out after {seconds} seconds and {attempts} attempts.")

        @wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            if seconds is None:
                return await func(*args, **kwargs)

            for a in range(attempts):
                try:
                    if os.environ.get("ENABLE_TIMEOUT_ASSERTION"):
                        return await asyncio.wait_for(func(*args, **kwargs), timeout=seconds)
                    else:
                        return await func(*args, **kwargs)
                except asyncio.TimeoutError:
                    if a < attempts - 1:
                        continue
                    if on_timeout is not None:
                        if callable(on_timeout):
                            result = on_timeout()

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Diagnose the underlying dependency the function contacts (redis-cli ping, mysql connect, curl the API) — the timeout is a symptom, not the fault.
  2. Raise the decorator's seconds/attempts for legitimately slow operations.
  3. Fix network-level issues: firewall dropping SYNs, wrong host/port, DNS misconfiguration.
  4. Note the abandoned daemon thread still holds resources; avoid retry storms that accumulate threads.

Example fix

# before
@timeout(seconds=5)
def fetch(): ...  # hangs on dead redis
# after
@timeout(seconds=30, attempts=3)
def fetch(): ...  # plus fix redis host/port
Defensive patterns

Strategy: retry

Validate before calling

import socket
def endpoint_reachable(host: str, port: int, timeout: float = 2.0) -> bool:
    try:
        socket.create_connection((host, port), timeout=timeout).close()
        return True
    except OSError:
        return False

Try / catch

from common.connection_utils import timeout
try:
    result = fetch_via_decorator()
except TimeoutError as e:
    # decorator already retried `attempts` times; escalate to circuit breaker / alert
    log.error("%s", e)
    raise

Prevention

When it happens

Trigger: Calling a sync function decorated with @timeout(seconds=N, attempts=M) with ENABLE_TIMEOUT_ASSERTION in the environment, where the underlying call blocks longer than N seconds on every attempt — typical for Redis/DB/network calls that hang. The thread itself keeps running (daemon, abandoned); only the caller gives up.

Common situations: Redis or MySQL unreachable/black-holing packets (no RST, just dropped) so a socket read hangs; test suites setting ENABLE_TIMEOUT_ASSERTION to keep CI fast; slow downstream LLM/API calls exceeding the configured budget; DNS hangs.

Understand the failure class

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/96f0ff9ec3decda2. Report an issue: GitHub.