diff --git a/sqlit/domains/process_worker/app/process_worker.py b/sqlit/domains/process_worker/app/process_worker.py index 3a79a5fd..2339a6c3 100644 --- a/sqlit/domains/process_worker/app/process_worker.py +++ b/sqlit/domains/process_worker/app/process_worker.py @@ -79,9 +79,6 @@ def send(self, payload: dict[str, Any]) -> None: try: self.conn.send(payload) return - except OSError: - # Pipe closed; nothing we can do. - return except Exception as exc: # Result couldn't be serialized: not picklable, or a driver # error raised while pickling — e.g. oracledb LOB locators diff --git a/tests/unit/test_process_worker_pickle_safety.py b/tests/unit/test_process_worker_pickle_safety.py index 3482ce49..7f785d83 100644 --- a/tests/unit/test_process_worker_pickle_safety.py +++ b/tests/unit/test_process_worker_pickle_safety.py @@ -135,6 +135,35 @@ def __reduce__(self) -> Any: raise RuntimeError("DPY-1001: not connected to database") +class _RaisesOSErrorOnPickle: + """Simulate serialization code raising an exception also used by pipes.""" + + def __reduce__(self) -> Any: + raise OSError("LOB read failed") + + +def test_worker_send_pickle_raising_oserror_emits_error() -> None: + """An OSError during serialization must not be mistaken for a closed pipe.""" + state, parent = _make_state_with_pipe() + try: + payload: dict[str, Any] = { + "type": "result", + "id": 8, + "kind": "query", + "result": _RaisesOSErrorOnPickle(), + } + state.send(payload) + + assert parent.poll(timeout=2.0), "client would hang; no error message was sent" + message = parent.recv() + assert message["type"] == "error" + assert message["id"] == 8 + assert "LOB read failed" in message["message"] + finally: + parent.close() + state.conn.close() + + def test_worker_send_pickle_raising_driver_error_emits_error() -> None: """Regression test for issue #276: oracledb CLOB/BLOB results raised InterfaceError during pickling, which fell through to a bare