ZhuLinsen/daily_stock_analysis · error · DataFetchError

Baostock 登录失败: {login_result.error_msg}

Error message

Baostock 登录失败: {login_result.error_msg}

What it means

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.

Source

Thrown at data_provider/baostock_fetcher.py:115

        
        确保:
        1. 进入上下文时自动登录
        2. 退出上下文时自动登出
        3. 异常时也能正确登出
        
        使用示例:
            with self._baostock_session():
                # 在这里执行数据查询
        """
        bs = self._get_baostock()
        login_result = None
        
        try:
            # 登录 Baostock
            login_result = bs.login()
            
            if login_result.error_code != '0':
                raise DataFetchError(f"Baostock 登录失败: {login_result.error_msg}")
            
            logger.debug("Baostock 登录成功")
            
            yield bs
            
        finally:
            # 确保登出,防止连接泄露
            try:
                logout_result = bs.logout()
                if logout_result.error_code == '0':
                    logger.debug("Baostock 登出成功")
                else:
                    logger.warning(f"Baostock 登出异常: {logout_result.error_msg}")
            except Exception as e:
                logger.warning(f"Baostock 登出时发生错误: {e}")
    
    def _convert_stock_code(self, stock_code: str) -> str:
        """

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Retry after a wait — baostock outages are usually transient (check baostock's status/announcements).
  2. Test standalone: `import baostock as bs; bs.login()` in a REPL to isolate the service vs your code.
  3. Avoid concurrent baostock sessions (it is a module-level global connection); serialize fetches or use a lock.
  4. Upgrade the baostock package, then let the manager fall back to Akshare for A-shares.

Example fix

# before
with fetcher._baostock_session() as bs:
    ...  # single attempt, dies on outage

# after
for attempt in range(3):
    try:
        with fetcher._baostock_session() as bs:
            ...
        break
    except DataFetchError as e:
        if '登录失败' in str(e):
            time.sleep(30 * (attempt + 1))
        else:
            raise
Defensive patterns

Strategy: retry

Validate before calling

import baostock as bs
lg = bs.login()
if lg.error_code != '0':
    raise ConnectionError(f'baostock service unavailable: {lg.error_msg}')
bs.logout()

Try / catch

for attempt in range(3):
    try:
        with fetcher._baostock_session() as bs:
            df = fetch_under(bs)
        break
    except DataFetchError as e:
        if '登录失败' in str(e) and attempt < 2:
            time.sleep(30 * (attempt + 1))
        else:
            df = akshare_fetcher.fetch(code, start, end)
            break

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/6515a0ff5d8d72cd. Report an issue: GitHub.