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

  1. Check the caller of _call_with_timeout and print the timeout_seconds being passed for the failing task_name
  2. Set a positive timeout (e.g. 3-10s) in the relevant configuration entry
  3. If 0 was meant as 'use default', map 0/None to a sensible default before calling instead of passing it through
  4. 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

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

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/5f95f422c63a3a2f. Report an issue: GitHub.