@@ -93,12 +93,44 @@ <h2 class="section-title" id="header-classes">Classes</h2>
9393 logger.debug(f"MCP session cleanup cancelled {context}")
9494 return
9595
96- # Handle ExceptionGroup from task group failures (Python 3.11+)
97- if _ExceptionGroup is not None and isinstance(
98- cleanup_error, _ExceptionGroup
99- ):
100- for exc in cleanup_error.exceptions: # type: ignore[attr-defined]
101- self._log_cleanup_error(exc, context)
96+ # Handle ExceptionGroup/BaseExceptionGroup from task group failures (Python 3.11+)
97+ # ExceptionGroup: for Exception subclasses (e.g., HTTPStatusError)
98+ # BaseExceptionGroup: for BaseException subclasses (e.g., CancelledError)
99+ # We need both because CancelledError is a BaseException, not an Exception
100+ is_exception_group = (
101+ _ExceptionGroup is not None and isinstance(cleanup_error, _ExceptionGroup)
102+ ) or (
103+ _BaseExceptionGroup is not None
104+ and isinstance(cleanup_error, _BaseExceptionGroup)
105+ )
106+
107+ if is_exception_group:
108+ # Check if all exceptions in the group are CancelledError
109+ # If so, treat the entire group as a cancellation
110+ all_cancelled = all(
111+ isinstance(exc, asyncio.CancelledError)
112+ for exc in cleanup_error.exceptions # type: ignore[attr-defined]
113+ )
114+ if all_cancelled:
115+ logger.debug(f"MCP session cleanup cancelled {context}")
116+ return
117+
118+ # Mixed group: skip CancelledErrors and log real errors
119+ exceptions = cleanup_error.exceptions # type: ignore[attr-defined]
120+ cancelled_errors = [
121+ exc for exc in exceptions if isinstance(exc, asyncio.CancelledError)
122+ ]
123+ cancelled_count = len(cancelled_errors)
124+ if cancelled_count > 0:
125+ logger.debug(
126+ f"Skipping {cancelled_count} CancelledError(s) "
127+ f"in mixed exception group {context}"
128+ )
129+
130+ # Log each non-cancelled exception individually
131+ for exc in exceptions:
132+ if not isinstance(exc, asyncio.CancelledError):
133+ self._log_cleanup_error(exc, context)
102134 else:
103135 self._log_cleanup_error(cleanup_error, context)
104136
@@ -113,7 +145,9 @@ <h2 class="section-title" id="header-classes">Classes</h2>
113145 and ("cancel scope" in exc_str or "async context" in exc_str)
114146 ) or (
115147 # HTTP errors during cleanup (if httpx is available)
116- HTTPX_AVAILABLE and HTTPStatusError is not None and isinstance(exc, HTTPStatusError)
148+ HTTPX_AVAILABLE
149+ and HTTPStatusError is not None
150+ and isinstance(exc, HTTPStatusError)
117151 )
118152
119153 if is_known_cleanup_error:
0 commit comments