ZhuLinsen/daily_stock_analysis · error · ValueError
题材新闻搜索超时必须大于 0 秒
Error message
题材新闻搜索超时必须大于 0 秒
What it means
Raised by SearchService topic-news search (src/search_service.py:3961) when timeout_seconds is parsed as a float and is <= 0. The method enforces a strictly positive, caller-supplied deadline budget before it ever touches cache or subprocess, so a zero/negative timeout is treated as a programming or config error rather than silently running unbounded.
Source
Thrown at src/search_service.py:3961
max_results: int = 5,
focus_keywords: Optional[List[str]] = None,
*,
timeout_seconds: float = 12.0,
) -> SearchResponse:
"""Search topic news within one cache-wait and provider deadline."""
topic_text = (topic or "").strip()
if not topic_text or not self.is_available:
return SearchResponse(
query=topic_text,
results=[],
provider="None",
success=False,
error_message="未配置搜索能力或题材为空",
)
wait_seconds = float(timeout_seconds)
if wait_seconds <= 0:
raise ValueError("题材新闻搜索超时必须大于 0 秒")
deadline = time.monotonic() + wait_seconds
search_days = self._effective_news_window_days()
query_terms = [str(item).strip() for item in (focus_keywords or []) if str(item).strip()]
query = " ".join(query_terms) if query_terms else f'"{topic_text}" A股 最新消息 催化'
cache_key = self._cache_key(f"topic_news:{topic_text}:{query}", max_results, search_days)
cached, cache_owner, cache_event, _waited = self._get_cached_or_wait_for_reservation(
cache_key,
deadline=deadline,
)
if cached is not None:
return cached
try:
remaining = deadline - time.monotonic()
if remaining <= 0:
raise TimeoutError("题材新闻搜索等待超过调用截止时间")
response = _call_topic_news_in_subprocess(
constructor_kwargs=self._constructor_kwargs,View on GitHub (pinned to 5159bd72e8)
Solutions
- Pass a positive timeout in seconds, e.g. timeout_seconds=30.
- If the timeout comes from config/env, add a sane default (e.g. int(os.getenv('TOPIC_NEWS_TIMEOUT', '30'))) so unset does not become 0.
- If the value is a remaining-budget computed from a deadline, check it before calling and skip/handle the exhausted case instead of letting the ValueError fire.
- Audit the call site for unit confusion (ms vs s) and convert explicitly.
Example fix
// before
response = search_service.search_topic_news(
topic="机器人", timeout_seconds=0 # meant 'no limit'
)
// after
response = search_service.search_topic_news(
topic="机器人", timeout_seconds=30.0
) Defensive patterns
Strategy: validation
Validate before calling
timeout = float(timeout_seconds)
if not (timeout > 0) or timeout != timeout:
raise ValueError('configure a positive topic-news timeout')
response = svc.search_topic_news(topic=topic, timeout_seconds=timeout) Type guard
def is_positive_timeout(v) -> bool:
try:
return float(v) > 0
except (TypeError, ValueError):
return False Try / catch
try:
resp = svc.search_topic_news(topic=t, timeout_seconds=ts)
except ValueError as e:
if '超时必须大于 0' in str(e):
ts = 30.0 # fall back to a sane default and retry once
resp = svc.search_topic_news(topic=t, timeout_seconds=ts)
else:
raise Prevention
- Never use 0 as a 'no timeout' sentinel for this API; omit or use a positive default.
- Centralize timeout constants in config with positive-value validation.
- Unit-test the call path with timeout_seconds in {0, -1, '0.0'} to catch regressions early.
When it happens
Trigger: Calling search_topic_news (the topic news entrypoint in src/search_service.py) with timeout_seconds=0, a negative number, or a numeric string like '-1' / '0.0' that float() accepts. Also triggered when a config/env value that feeds timeout_seconds (e.g. a topic-news timeout setting) is unset and coerced to 0.
Common situations: Passing seconds vs milliseconds by mistake (timeout_seconds=500 intended as ms becomes a huge value, but timeout_seconds=0 passed as a 'no timeout' sentinel); wiring an env var like TOPIC_NEWS_TIMEOUT into the call without a default; a caller computing remaining = deadline - now and passing a computed 0 when the budget is already exhausted.
Related errors
- validation_failed
- capability_unsupported
- Responses API surface requires a normalized openai/<model> r
- LLM route aliases cannot mix API surfaces: {sorted(surface_c
- eval_window_days must be positive
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/48579e28673099c2.
Report an issue: GitHub.