{"record":{"id":"6ed75b9f5ba03810","repo":"ZhuLinsen/daily_stock_analysis","slug":"tickflow-daily-k-line-request-failed-exc","errorCode":null,"errorMessage":"TickFlow daily K-line request failed: {exc}","messagePattern":"TickFlow daily K-line request failed: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/tickflow_fetcher.py","lineNumber":197,"sourceCode":"            return cached\n\n        client = self._get_client()\n        if client is None:\n            raise DataFetchError(\"TickFlow API key is not configured\")\n\n        request_count = self._daily_kline_count(start_date, end_date)\n        try:\n            df = client.klines.get(\n                symbol,\n                period=\"1d\",\n                count=request_count,\n                start_time=self._date_to_ms(start_date),\n                end_time=self._date_to_ms(end_date, end_of_day=True),\n                adjust=self.kline_adjust,\n                as_dataframe=True,\n            )\n        except Exception as exc:\n            raise DataFetchError(f\"TickFlow daily K-line request failed: {exc}\") from exc\n\n        raw_df = self._prepare_daily_frame(\n            df,\n            symbol=symbol,\n            start_date=start_date,\n            end_date=end_date,\n            count=request_count,\n            context=\"single\",\n        )\n        self._set_daily_cache(cache_key, raw_df)\n        return raw_df.copy()\n\n    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:\n        raw = self._coerce_frame(df)\n        if raw.empty:\n            return pd.DataFrame(columns=[\"code\", *STANDARD_COLUMNS])\n\n        normalized = pd.DataFrame()","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/tickflow_fetcher.py#L179-L215","documentation":"DataFetchError raised when the client.klines.get(...) call to the TickFlow API throws any exception (HTTP error, timeout, SDK error, malformed response). The original exception is chained ('from exc') so the root cause stays visible; no partial data is returned.","triggerScenarios":"TickFlow HTTP API unreachable, 4xx/5xx responses, rate limiting, expired/invalid API key producing auth errors, or SDK deserialization failures while fetching daily klines with period='1d'.","commonSituations":"TickFlow service outage; quota exhausted; network egress blocked from the runtime host; key revoked; SDK version drift changing exception types.","solutions":["Log and inspect exc.__cause__ to classify: auth (fix key), rate limit (back off), network (fix egress), or 5xx (wait/fallback).","Catch DataFetchError in the manager and fall back to Akshare/Tencent for A-share daily data.","For predictable transient failures, rely on the project's retry/fallback layer rather than tight loops against TickFlow."],"exampleFix":"# before\ntry:\n    df = tickflow_fetcher.get_stock_data(code, start, end)\nexcept DataFetchError:\n    raise\n\n# after\ntry:\n    df = tickflow_fetcher.get_stock_data(code, start, end)\nexcept DataFetchError as e:\n    logger.warning(f\"TickFlow failed ({e.__cause__}), falling back to akshare\")\n    df = akshare_fetcher.get_stock_data(code, start, end)","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    df = tickflow_fetcher.get_stock_data(code, start, end)\nexcept DataFetchError as e:\n    cause = str(e.__cause__ or \"\")\n    logger.warning(f\"TickFlow kline error: {cause}\")\n    df = akshare_fetcher.get_stock_data(code, start, end)  # transient/outage fallback","preventionTips":["Classify the chained cause (auth vs rate-limit vs network) before choosing retry vs fallback.","Monitor TickFlow error rates and disable the provider automatically when it degrades.","Cache successful responses (the fetcher already caches) to ride out short outages."],"tags":["tickflow","http-api","transient","fallback"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}