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
- Diagnose the underlying dependency the function contacts (redis-cli ping, mysql connect, curl the API) — the timeout is a symptom, not the fault.
- Raise the decorator's seconds/attempts for legitimately slow operations.
- Fix network-level issues: firewall dropping SYNs, wrong host/port, DNS misconfiguration.
- 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
- Set realistic seconds/attempts per dependency (DB vs LLM differ by orders of magnitude).
- Verify host/port reachability before long-running jobs.
- Remember the sync wrapper abandons a daemon thread per timeout — avoid tight outer retry loops.
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Operation timed out after {seconds} seconds and {attempts} a
- Execution timed out after {exec_timeout} seconds
- Failed to fetch {current_url!r}: {_exc}
- Unexpected validation error: {e}
- WhatsApp session is not running.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/96f0ff9ec3decda2.
Report an issue: GitHub.