From 225cbacaaa798c918da63d74b5dc7c05a1763064 Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Wed, 4 Feb 2026 15:28:43 -0500 Subject: [PATCH 1/2] fix: handle BrokenPipeError in LMHandler during parallel execution When running parallel evaluations, multiple workers connect to the LMHandler socket server. When workers complete and close their sockets, BrokenPipeError was raised during response transmission, causing noisy error output. Changes: - Add _safe_send() helper that catches connection errors silently - Handle BrokenPipeError, ConnectionError, ConnectionResetError, and OSError separately from other exceptions - Use _safe_send() for all socket_send() calls in handle() method This prevents cascading errors where the exception handler tried to send an error response on an already-broken socket. Co-Authored-By: Claude Opus 4.5 --- rlm/core/lm_handler.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/rlm/core/lm_handler.py b/rlm/core/lm_handler.py index 9eb751011..db8b36b30 100644 --- a/rlm/core/lm_handler.py +++ b/rlm/core/lm_handler.py @@ -22,7 +22,7 @@ def handle(self): request_data = socket_recv(self.connection) if not isinstance(request_data, dict): response = LMResponse.error_response("Request must be a JSON object") - socket_send(self.connection, response.to_dict()) + self._safe_send(response) return request = LMRequest.from_dict(request_data) @@ -37,11 +37,26 @@ def handle(self): else: response = LMResponse.error_response("Missing 'prompt' or 'prompts' in request.") - socket_send(self.connection, response.to_dict()) + self._safe_send(response) + + except (BrokenPipeError, ConnectionError, ConnectionResetError, OSError) as e: + # Client disconnected - this is expected during parallel execution + # when workers complete and close their sockets. Silently ignore. + pass except Exception as e: + # Try to send error response, but don't fail if socket is broken response = LMResponse.error_response(str(e)) + self._safe_send(response) + + def _safe_send(self, response: LMResponse) -> bool: + """Send response, returning False if the socket is broken.""" + try: socket_send(self.connection, response.to_dict()) + return True + except (BrokenPipeError, ConnectionError, ConnectionResetError, OSError): + # Client disconnected - silently ignore + return False def _handle_single(self, request: LMRequest, handler: "LMHandler") -> LMResponse: """Handle a single prompt request.""" From f1cc2d65b42a84a201d4e3fcb50055e298968077 Mon Sep 17 00:00:00 2001 From: Alex Zhang Date: Wed, 4 Feb 2026 15:37:19 -0500 Subject: [PATCH 2/2] linting --- rlm/core/lm_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rlm/core/lm_handler.py b/rlm/core/lm_handler.py index db8b36b30..9d63752dd 100644 --- a/rlm/core/lm_handler.py +++ b/rlm/core/lm_handler.py @@ -39,7 +39,7 @@ def handle(self): self._safe_send(response) - except (BrokenPipeError, ConnectionError, ConnectionResetError, OSError) as e: + except (BrokenPipeError, ConnectionError, ConnectionResetError, OSError): # Client disconnected - this is expected during parallel execution # when workers complete and close their sockets. Silently ignore. pass