Skip to content

unhandled errors in a TaskGroup (1 sub-exception) when use pyinstaller with --noconsole #2432

@tehnplk

Description

@tehnplk

Initial Checks

Description

unhandled errors in a TaskGroup (1 sub-exception)
  + Exception Group Traceback (most recent call last):
  |   File "AgentWorker.py", line 45, in run
  |   File "asyncio\base_events.py", line 691, in run_until_complete
  |   File "AgentWorker.py", line 23, in chat
  |   File "pydantic_ai\agent.py", line 551, in run
  |     async with self.iter(
  |                ^^^^^^^^^^
  |   File "contextlib.py", line 210, in __aenter__
  |   File "pydantic_ai\agent.py", line 777, in iter
  |     async with toolset:
  |                ^^^^^^^
  |   File "pydantic_ai\toolsets\combined.py", line 48, in __aenter__
  |     await exit_stack.enter_async_context(toolset)
  |   File "contextlib.py", line 659, in enter_async_context
  |   File "pydantic_ai\mcp.py", line 204, in __aenter__
  |     async with AsyncExitStack() as exit_stack:
  |                ^^^^^^^^^^^^^^^^
  |   File "contextlib.py", line 754, in __aexit__
  |   File "contextlib.py", line 737, in __aexit__
  |   File "contextlib.py", line 231, in __aexit__
  |   File "pydantic_ai\mcp.py", line 411, in client_streams
  |     async with stdio_client(server=server) as (read_stream, write_stream):
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "contextlib.py", line 231, in __aexit__
  |   File "mcp\client\stdio\__init__.py", line 181, in stdio_client
  |   File "anyio\_backends\_asyncio.py", line 772, in __aexit__
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "mcp\client\stdio\__init__.py", line 187, in stdio_client
    |   File "pydantic_ai\mcp.py", line 412, in client_streams
    |     yield read_stream, write_stream
    |   File "contextlib.py", line 737, in __aexit__
    |   File "mcp\shared\session.py", line 218, in __aexit__
    |   File "anyio\_backends\_asyncio.py", line 772, in __aexit__
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "pydantic_ai\mcp.py", line 216, in __aenter__
      |     await self._client.initialize()
      |   File "mcp\client\session.py", line 151, in initialize
      |   File "mcp\shared\session.py", line 286, in send_request
      | mcp.shared.exceptions.McpError: Connection closed
      +------------------------------------

Example Code

Python, Pydantic AI & LLM client version

from PyQt6.QtCore import QThread, pyqtSignal
from dotenv import load_dotenv
load_dotenv()

class AgentWorker(QThread):
    signal_finished = pyqtSignal(str)
    signal_error = pyqtSignal(str)
    signal_progress = pyqtSignal(str)
    signal_message_history = pyqtSignal(list)

    def __init__(self, agent, user_input, message_history):
        super().__init__()
        self.agent = agent
        self.user_input = user_input
        self.message_history = message_history
        self.new_message_history = []

    async def chat(self):
        try:
            async with self.agent.run_mcp_servers():
                result = await self.agent.run(
                    self.user_input, message_history=self.message_history
                )
                self.new_message_history = result.all_messages()
                self.signal_message_history.emit(self.new_message_history)

                self.signal_progress.emit("สำเร็จ")
                if getattr(result.output, "sql", None):
                    self.signal_finished.emit(result.output.sql)
                else:
                    self.signal_finished.emit(getattr(result.output, "explanation", ""))
        except Exception as e:
            # Re-raise so run() catches it and logs
            raise

    def run(self):
        import traceback, logging, asyncio
        loop = asyncio.new_event_loop()
        loop.set_exception_handler(lambda l, c: logging.error(
            f"Asyncio exception: {c.get('message')}", exc_info=c.get('exception')))
        asyncio.set_event_loop(loop)
        try:
            loop.run_until_complete(self.chat())
        except Exception as e:
            self.signal_error.emit(f"{e}\n{traceback.format_exc()}")
        finally:
            try:
                pending = asyncio.all_tasks(loop)
                for task in pending:
                    task.cancel()
                if pending:
                    loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
            finally:
                loop.close()

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions