{"record":{"id":"e2428da909780c9d","repo":"ZhuLinsen/daily_stock_analysis","slug":"finnhub-api-key-not-configured","errorCode":null,"errorMessage":"[Finnhub] API key not configured","messagePattern":"\\[Finnhub\\] API key not configured","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/finnhub_fetcher.py","lineNumber":43,"sourceCode":"\n\nclass FinnhubFetcher(BaseFetcher):\n    name = \"FinnhubFetcher\"\n    priority = 2\n\n    def __init__(self):\n        from src.config import get_config\n        config = get_config()\n        self._api_key = getattr(config, 'finnhub_api_key', None) or os.getenv('FINNHUB_API_KEY')\n        if not self._api_key:\n            logger.debug(\"[Finnhub] API key not configured, fetcher disabled\")\n\n    def _is_us_stock(self, stock_code: str) -> bool:\n        return is_us_stock_code(stock_code)\n\n    def _fetch_raw_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:\n        if not self._api_key:\n            raise DataFetchError(\"[Finnhub] API key not configured\")\n        if not self._is_us_stock(stock_code):\n            raise DataFetchError(f\"[Finnhub] {stock_code} is not a US stock\")\n\n        symbol = stock_code.strip().upper()\n        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)","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/finnhub_fetcher.py#L25-L61","documentation":"FinnhubFetcher refuses to fetch when no API key is resolvable: __init__ reads config.finnhub_api_key or env FINNHUB_API_KEY, and _fetch_raw_data hard-guards on the result. The constructor only logs at debug ('fetcher disabled'), so the first visible symptom is often this DataFetchError at fetch time.","triggerScenarios":"Calling FinnhubFetcher._fetch_raw_data/get_daily_data with neither config.finnhub_api_key nor the FINNHUB_API_KEY env var set — common in fresh clones, CI, or Docker images that don't pass the env var.","commonSituations":".env missing FINNHUB_API_KEY; docker run without -e FINNHUB_API_KEY; GitHub Actions secret not wired; config loaded before .env is read so getattr returns None.","solutions":["Set FINNHUB_API_KEY in .env (and .env.example documentation) or via environment for the process/container.","Confirm the value reaches get_config() — print/log whether config.finnhub_api_key is populated at startup.","If intentionally keyless, rely on manager routing (YFinance) instead of calling FinnhubFetcher directly; treat this error as 'source disabled'."],"exampleFix":"# before: nothing set -> raise\n# after: .env\nFINNHUB_API_KEY=your_key_here","handlingStrategy":"validation","validationCode":"import os\nfrom src.config import get_config\ncfg = get_config()\nhas_key = bool(getattr(cfg, 'finnhub_api_key', None) or os.getenv('FINNHUB_API_KEY'))\nif not has_key:\n    logger.info('Finnhub disabled — relying on YFinance/AlphaVantage for US')","typeGuard":"def finnhub_configured() -> bool:\n    return bool(getattr(get_config(), 'finnhub_api_key', None) or os.getenv('FINNHUB_API_KEY'))","tryCatchPattern":"try:\n    df = finnhub.get_daily_data(symbol, ...)\nexcept DataFetchError as e:\n    if 'API key not configured' in str(e):\n        skip_source('finnhub')  # config issue — do not retry","preventionTips":["Check key presence at startup and log which sources are enabled/disabled.","Pass FINNHUB_API_KEY explicitly in Docker/CI environments.","Treat 'not configured' as a permanent skip, distinct from network errors."],"tags":["finnhub","configuration","api-key","env"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}