jd-opensource/joyagent-jdgenie · error · Exception
认证失败 - 无效的凭据
Error message
认证失败 - 无效的凭据
What it means
Raised by `_sse_connection` in the MCP SSE client when the server responds with an authentication failure (401) during the SSE handshake. The original exception is inspected by `_is_authentication_error` and re-raised as a generic Exception with this message. It means the configured credentials (API key/token) are missing, malformed, or rejected by the server.
Solutions
- Verify the API key/token configured on the client (constructor/headers) is current and correct for this server_url
- Check the Authorization header is actually being attached (log or inspect the client config before connect)
- Curl the SSE endpoint manually with the same header to confirm the credential works outside the library
- Re-generate or rotate credentials from the server admin console and restart the client
Example fix
// before
client = SseClient(server_url=URL) # no auth headers
// after
client = SseClient(server_url=URL, headers={"Authorization": f"Bearer {os.environ['MCP_TOKEN']}"}) Defensive patterns
Strategy: try-catch
Validate before calling
token = os.environ.get("MCP_TOKEN")
if not token:
raise RuntimeError("MCP_TOKEN not set")
# optionally: curl the endpoint with the header before connecting Type guard
def has_credentials(client) -> bool:
return bool(getattr(client, "headers", {}).get("Authorization")) Try / catch
try:
await client.ping_server()
except Exception as e:
if "认证失败" in str(e):
refresh_credentials_and_retry()
else:
raise Prevention
- Load credentials from env/config at startup and fail fast if missing
- Rotate tokens before expiry and restart dependent clients
- Test auth with a cheap ping_server call before heavier operations
When it happens
Trigger: Any of ping_server, list_tools, or call_tool opens an SSE session (`_sse_connection`) while the HTTP connection is rejected with 401 Unauthorized — e.g. expired/invalid API key, wrong auth header, or server auth policy change.
Common situations: Environment variable holding the token not set or pointing at the wrong server; token rotated or revoked upstream; missing `Authorization` header configuration in the client constructor; using a staging token against production.
Related errors
AI-assisted analysis of jd-opensource/joyagent-jdgenie@2417e0b8b6 (2026-09-08).
Data as JSON: /api/errors/723a431e89042d88.
Report an issue: GitHub.
Appendix: source
Thrown at genie-client/app/client.py:146
streams = await self._streams_context.__aenter__()
logger.debug(f"[{connection_id}] SSE流连接已建立")
# 创建客户端会话
self._session_context = ClientSession(*streams)
session = await self._session_context.__aenter__()
logger.debug(f"[{connection_id}] 客户端会话已创建")
# 初始化会话,可能触发认证验证
await session.initialize()
logger.info(f"[{connection_id}] SSE连接建立成功")
yield session
except Exception as e:
# 根据异常类型进行不同的处理
if self._is_authentication_error(e):
logger.error(f"[{connection_id}] 认证失败 - 401 未授权")
raise Exception("认证失败 - 无效的凭据") from e
elif self._is_network_error(e):
logger.error(f"[{connection_id}] 网络连接失败: {str(e)}")
raise Exception(f"网络连接失败: {str(e)}") from e
else:
logger.error(f"[{connection_id}] SSE连接失败: {str(e)}")
raise
finally:
# 确保资源被正确清理
await self._cleanup_connection(connection_id)
@staticmethod
def _is_authentication_error(exception: Exception) -> bool:
"""
检查异常是否为认证错误 (401 Unauthorized)
Args:
exception: 待检查的异常对象
View on GitHub (pinned to 2417e0b8b6)