ZhuLinsen/daily_stock_analysis · error · DataFetchError
[{self.name}] {stock_code}: {error_reason}
Error message
[{self.name}] {stock_code}: {error_reason} What it means
The catch-all wrapper in BaseFetcher.get_daily_data: any exception escaping the pipeline (fetch, _normalize_data, _clean_data, _calculate_indicators) or re-raised from steps 1-3 is summarized via summarize_exception and re-raised as DataFetchError with the original as __cause__. The message '获取失败' with error_type/reason in the preceding log line is the diagnostic.
Source
Thrown at data_provider/base.py:528
# Step 4: 计算技术指标
df = self._calculate_indicators(df)
elapsed = time.time() - request_start
logger.info(
f"[{self.name}] {stock_code} 获取成功: 范围={start_date} ~ {end_date}, "
f"rows={len(df)}, elapsed={elapsed:.2f}s"
)
return df
except Exception as e:
elapsed = time.time() - request_start
error_type, error_reason = summarize_exception(e)
logger.error(
f"[{self.name}] {stock_code} 获取失败: 范围={start_date} ~ {end_date}, "
f"error_type={error_type}, elapsed={elapsed:.2f}s, reason={error_reason}"
)
raise DataFetchError(f"[{self.name}] {stock_code}: {error_reason}") from e
def _clean_data(self, df: pd.DataFrame) -> pd.DataFrame:
"""
数据清洗
处理:
1. 确保日期列格式正确
2. 数值类型转换
3. 去除空值行
4. 按日期排序
"""
df = df.copy()
# 确保日期列为 datetime 类型
if 'date' in df.columns:
df['date'] = pd.to_datetime(df['date'])
# 数值列类型转换View on GitHub (pinned to 5159bd72e8)
Solutions
- Read the 'error_type=..., reason=...' in the logged '获取失败' line immediately before the raise — it names the root exception, not this wrapper.
- Reproduce with a direct call to the failing step (e.g. fetcher._normalize_data(raw_df, code)) on the logged date range to isolate which pipeline stage threw.
- Fix the root cause in the responsible step (column mapping, dtype coercion, indicator guard) rather than catching DataFetchError at the call site.
Defensive patterns
Strategy: fallback
Try / catch
try:
df = manager.get_daily_data(code, ...)
except DataFetchError as e:
logger.warning('daily fetch failed for %s: %s', code, e)
df = load_cached_daily(code) # or skip / use next market source Prevention
- Always log the chained __cause__ — the root exception is one attribute away: e.__cause__.
- Add contract tests asserting provider response schemas before normalizers run.
- Keep per-step try boundaries in custom fetchers so failures carry the failing stage name.
When it happens
Trigger: Any unhandled exception inside _fetch_raw_data, _normalize_data, _clean_data, or _calculate_indicators: schema drift (missing columns), type coercion failures, indicator math errors on degenerate data (single row, all-NaN), or a lower-level DataFetchError/RateLimitError being re-wrapped.
Common situations: Provider renames/drops a column so normalization raises KeyError; technical indicator division by zero on flat data; network errors from the fetch step bubbling up with the elapsed-time context attached.
Related errors
- {call_name} 调用超过 {wait_seconds:g}s,已放弃等待
- Baostock 获取数据失败: {e}
- [{self.name}] 未获取到 {stock_code} 的数据
- 大盘复盘未返回可持久化报告
- {call_name} 调用进程未返回结果
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/d5da71d7d0c299ab.
Report an issue: GitHub.