ZhuLinsen/daily_stock_analysis · error · TimeoutError
{task_name} ranking fetch timeout
Error message
{task_name} ranking fetch timeout What it means
TimeoutError(f'{task_name} ranking fetch timeout') is raised by MarketHotspotService._call_with_timeout when the configured timeout_seconds is zero or negative (timeout_value = max(0.0, float(timeout_seconds)); if timeout_value <= 0 it raises immediately). It is a configuration/validation failure raised before any fetch is attempted — distinct from the 'after {n}s' variant which reflects a real elapsed timeout.
Source
Thrown at src/services/market_hotspot_service.py:428
"fundamental_fetch_timeout_seconds",
DEFAULT_RANKING_FETCH_TIMEOUT_SECONDS,
)
return max(0.0, float(value))
except Exception:
return DEFAULT_RANKING_FETCH_TIMEOUT_SECONDS
@classmethod
def _call_with_timeout(
cls,
task: Callable[[], Any],
*,
timeout_seconds: float,
task_name: str,
inflight_key: Optional[Hashable] = None,
) -> Any:
timeout_value = max(0.0, float(timeout_seconds))
if timeout_value <= 0:
raise TimeoutError(f"{task_name} ranking fetch timeout")
effective_inflight_key = inflight_key or task_name
future = cls._get_or_submit_ranking_fetch(
task,
inflight_key=effective_inflight_key,
task_name=task_name,
)
try:
return future.result(timeout=timeout_value)
except FutureTimeoutError as exc:
if future.done() and future.exception(timeout=0) is exc:
raise
cls._mark_ranking_fetch_timeout(
effective_inflight_key,
future,
retry_after=time.monotonic()
+ max(timeout_value, RANKING_FETCH_TIMEOUT_RETRY_DELAY_SECONDS),
)View on GitHub (pinned to 5159bd72e8)
Solutions
- Check the caller of _call_with_timeout and print the timeout_seconds being passed for the failing task_name
- Set a positive timeout (e.g. 3-10s) in the relevant configuration entry
- If 0 was meant as 'use default', map 0/None to a sensible default before calling instead of passing it through
- Guard unit tests that intentionally pass 0 with pytest.raises(TimeoutError)
Example fix
# before
timeout_seconds = int(os.getenv("RANKING_TIMEOUT", "0"))
# after: default to 5s when unset or zero
timeout_seconds = int(os.getenv("RANKING_TIMEOUT", "5") or "5")
timeout_seconds = timeout_seconds if timeout_seconds > 0 else 5 Defensive patterns
Strategy: validation
Validate before calling
timeout_seconds = float(timeout_seconds)
if timeout_seconds <= 0:
timeout_seconds = DEFAULT_RANKING_TIMEOUT # e.g. 5.0
# now safe to call _call_with_timeout Type guard
def is_positive_timeout(value: Any) -> bool:
try:
return float(value) > 0
except (TypeError, ValueError):
return False Prevention
- Clamp configured timeouts to a sane positive default at load time
- Treat 0/empty config values as 'unset', never as a valid timeout
- Unit-test the timeout configuration path
When it happens
Trigger: Calling _call_with_timeout (directly or via a ranking fetch helper) with timeout_seconds=0, a negative number, or a value that float()s to 0 (e.g. '0', 0.0); typically a miscomputed timeout from configuration like timeout = base * factor where factor is 0.
Common situations: A config knob (e.g. ranking fetch timeout) set to 0 in .env intending 'no wait' but meaning 'fail fast', unit tests passing 0 to force timeout paths, or a timeout derived from a market-hours calculation that returns 0 outside trading windows.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- TUSHARE_HTTP_URL 必须以 http:// 或 https:// 开头,当前值为 {url!r}
- FUTU_OPEND_PORT 不是有效端口: {raw_port!r}
- Futu OpenD 地址无效: {host!r}:{port}
- FUTU_ACC_ID 必须是正整数账户 ID
- 不支持的 FUTU_SECURITY_FIRM: {name}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/5f95f422c63a3a2f.
Report an issue: GitHub.