{"record":{"id":"6515a0ff5d8d72cd","repo":"ZhuLinsen/daily_stock_analysis","slug":"baostock-login-result-error-msg","errorCode":null,"errorMessage":"Baostock 登录失败: {login_result.error_msg}","messagePattern":"Baostock 登录失败: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/baostock_fetcher.py","lineNumber":115,"sourceCode":"        \n        确保：\n        1. 进入上下文时自动登录\n        2. 退出上下文时自动登出\n        3. 异常时也能正确登出\n        \n        使用示例：\n            with self._baostock_session():\n                # 在这里执行数据查询\n        \"\"\"\n        bs = self._get_baostock()\n        login_result = None\n        \n        try:\n            # 登录 Baostock\n            login_result = bs.login()\n            \n            if login_result.error_code != '0':\n                raise DataFetchError(f\"Baostock 登录失败: {login_result.error_msg}\")\n            \n            logger.debug(\"Baostock 登录成功\")\n            \n            yield bs\n            \n        finally:\n            # 确保登出，防止连接泄露\n            try:\n                logout_result = bs.logout()\n                if logout_result.error_code == '0':\n                    logger.debug(\"Baostock 登出成功\")\n                else:\n                    logger.warning(f\"Baostock 登出异常: {logout_result.error_msg}\")\n            except Exception as e:\n                logger.warning(f\"Baostock 登出时发生错误: {e}\")\n    \n    def _convert_stock_code(self, stock_code: str) -> str:\n        \"\"\"","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/baostock_fetcher.py#L97-L133","documentation":"A DataFetchError raised by BaostockFetcher._baostock_session when bs.login() returns a non-zero error_code. Baostock is a free login-based socket service; a failed login means no queries can run, and the context manager aborts before yielding so the logout in finally still runs, preventing connection leaks.","triggerScenarios":"baostock.login() failing due to: baostock service under maintenance or offline (common on weekends/holidays), network blocking the socket connection to baostock's server, an outdated/broken baostock package, or too many concurrent sessions holding the single global connection.","commonSituations":"Baostock's official servers are periodically unavailable — login errors come in waves for all users; running parallel workers where baostock's global singleton session collides; firewall blocking the baostock TCP endpoint in Docker/CI.","solutions":["Retry after a wait — baostock outages are usually transient (check baostock's status/announcements).","Test standalone: `import baostock as bs; bs.login()` in a REPL to isolate the service vs your code.","Avoid concurrent baostock sessions (it is a module-level global connection); serialize fetches or use a lock.","Upgrade the baostock package, then let the manager fall back to Akshare for A-shares."],"exampleFix":"# before\nwith fetcher._baostock_session() as bs:\n    ...  # single attempt, dies on outage\n\n# after\nfor attempt in range(3):\n    try:\n        with fetcher._baostock_session() as bs:\n            ...\n        break\n    except DataFetchError as e:\n        if '登录失败' in str(e):\n            time.sleep(30 * (attempt + 1))\n        else:\n            raise","handlingStrategy":"retry","validationCode":"import baostock as bs\nlg = bs.login()\nif lg.error_code != '0':\n    raise ConnectionError(f'baostock service unavailable: {lg.error_msg}')\nbs.logout()","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        with fetcher._baostock_session() as bs:\n            df = fetch_under(bs)\n        break\n    except DataFetchError as e:\n        if '登录失败' in str(e) and attempt < 2:\n            time.sleep(30 * (attempt + 1))\n        else:\n            df = akshare_fetcher.fetch(code, start, end)\n            break","preventionTips":["Pre-flight baostock login at job start to fail fast during known service outages.","Serialize baostock usage across threads — its session is a module-level global.","Schedule A-share jobs outside baostock's maintenance windows."],"tags":["baostock","login","service-outage","a-shares"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}