From f990fe5db1084f0a64e80e743a4ee4d2bc684362 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 14 Apr 2026 13:39:27 +0100 Subject: [PATCH] Report parallel worker exit status on receive failure --- mypy/build.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index ca7e6d486822..d7191034f18b 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -1294,10 +1294,21 @@ def broadcast(self, message: bytes) -> None: def wait_ack(self) -> None: """Wait for an ack from all workers.""" - for worker in self.workers: - buf = receive(worker.conn) + for idx in range(len(self.workers)): + buf = self.receive_worker_message(idx) assert read_tag(buf) == ACK_MESSAGE + def receive_worker_message(self, idx: int) -> ReadBuffer: + """Receive a single message from a worker, with crash diagnostics.""" + try: + return receive(self.workers[idx].conn) + except OSError as exc: + exit_code = self.workers[idx].proc.poll() + exit_status = f"exit code {exit_code}" if exit_code is not None else "still running" + raise OSError( + f"Worker {idx} disconnected before sending data ({exit_status})" + ) from exc + def submit(self, graph: Graph, sccs: list[SCC]) -> None: """Submit a stale SCC for processing in current process or parallel workers.""" if self.workers: @@ -1367,7 +1378,7 @@ def wait_for_done_workers( ready = ready_to_read([w.conn for w in self.workers], WORKER_DONE_TIMEOUT) t1 = time.time() for idx in ready: - buf = receive(self.workers[idx].conn) + buf = self.receive_worker_message(idx) assert read_tag(buf) == SCC_RESPONSE_MESSAGE data = SccResponseMessage.read(buf) if not data.is_interface: