{"record":{"id":"e934094dc3177541","repo":"ZhuLinsen/daily_stock_analysis","slug":"finnhub-http-request-failed-for-symbol-e","errorCode":null,"errorMessage":"[Finnhub] HTTP request failed for {symbol}: {e}","messagePattern":"\\[Finnhub\\] HTTP request failed for (.+?): (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/finnhub_fetcher.py","lineNumber":66,"sourceCode":"        start_ts = int(datetime.strptime(start_date, '%Y-%m-%d').timestamp())\n        end_ts = int(datetime.strptime(end_date, '%Y-%m-%d').timestamp())\n\n        url = f\"{_FINNHUB_BASE_URL}/stock/candle\"\n        params = {\n            'symbol': symbol,\n            'resolution': 'D',\n            'from': start_ts,\n            'to': end_ts,\n            'token': self._api_key,\n        }\n\n        try:\n            self.random_sleep(0.3, 0.8)\n            resp = requests.get(url, params=params, timeout=15)\n            resp.raise_for_status()\n            data = resp.json()\n        except Exception as e:\n            raise DataFetchError(f\"[Finnhub] HTTP request failed for {symbol}: {e}\") from e\n\n        if data.get('s') != 'ok' or not data.get('c'):\n            raise DataFetchError(f\"[Finnhub] No data returned for {symbol}\")\n\n        return pd.DataFrame({\n            'c': data['c'],\n            'h': data['h'],\n            'l': data['l'],\n            'o': data['o'],\n            't': data['t'],\n            'v': data['v'],\n        })\n\n    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:\n        if df.empty:\n            return df\n\n        df = df.copy()","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/finnhub_fetcher.py#L48-L84","documentation":"Network/HTTP failure in FinnhubFetcher._fetch_raw_data: requests.get (timeout=15) raised, raise_for_status saw a 4xx/5xx, or JSON decoding failed. The original exception is chained (__cause__) and embedded in the message, so the status code or timeout reason is visible verbatim.","triggerScenarios":"GET {FINNHUB_BASE_URL}/stock/candle with symbol/resolution/from/to/token — timeouts after 15s, 403 (invalid key / key disabled), 429 (free-tier 60 calls/min), DNS/TLS failures, or a non-JSON error page.","commonSituations":"Free-tier rate limit exhaustion (429) during batch US fetches; revoked API key (403); corporate proxy blocking finnhub.io; slow mobile networks hitting the 15s timeout.","solutions":["Inspect the embedded {e}: 429 -> slow down / upgrade plan; 403 -> reissue the API key; timeout -> retry once, then fail over to AlphaVantage/YFinance via the manager.","Add backoff between Finnhub calls to stay under the free-tier per-minute quota.","Verify network egress to finnhub.io (proxy/HTTP_PROXY settings) in containers and CI."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    df = finnhub.get_daily_data(symbol, ...)\nexcept DataFetchError as e:\n    msg = str(e)\n    if '429' in msg:\n        time.sleep(60); df = finnhub.get_daily_data(symbol, ...)\n    elif '403' in msg:\n        alert('Finnhub key rejected')\n    else:\n        df = manager.get_daily_data(symbol, ...)  # fail over","preventionTips":["Stay under Finnhub free-tier quota (60 req/min) with client-side throttling.","Set HTTP(S)_PROXY correctly in containerized runs.","Retry once on timeout, then fail over — the manager chain already encodes this."],"tags":["finnhub","network","http","timeout","retryable"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}