{"record":{"id":"0626d72efb130cd1","repo":"can1357/oh-my-pi","slug":"str-self-closed-error","errorCode":null,"errorMessage":"str(self._closed_error)","messagePattern":"str\\(self\\._closed_error\\)","errorType":"exception","errorClass":"RpcProcessExitError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":1336,"sourceCode":"        if streamed_prefix_count > len(streamed_messages):\n            raise RpcError(\n                \"Compacted agent_end references \"\n                f\"{streamed_prefix_count} streamed messages, but only \"\n                f\"{len(streamed_messages)} were retained\"\n            )\n        return streamed_messages[:streamed_prefix_count] + terminal.messages\n\n    def _wait_for_agent_end(\n        self,\n        start_index: int,\n        start_async_error_index: int,\n        timeout: float | None = None,\n    ) -> tuple[RpcAgentEvent, ...]:\n        deadline = time.monotonic() + (timeout if timeout is not None else 60.0)\n        with self._event_condition:\n            while True:\n                if self._closed_error is not None:\n                    raise RpcProcessExitError(str(self._closed_error))\n\n                if start_index < self._events.offset:\n                    raise RpcError(\n                        \"Event history limit was exceeded while waiting for agent_end. \"\n                        \"Increase max_event_history to retain more streamed events.\"\n                    )\n\n                if start_async_error_index < self._async_errors.offset:\n                    raise RpcError(\n                        \"Async error history limit was exceeded while waiting for agent_end. \"\n                        \"Increase max_event_history if your host needs to retain more background failures.\"\n                    )\n\n                async_errors = self._async_errors.snapshot_from(start_async_error_index)\n                if len(async_errors) > 0:\n                    raise async_errors[0]\n\n                event_payloads = self._events.snapshot_from(start_index)","sourceCodeStart":1318,"sourceCodeEnd":1354,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L1318-L1354","documentation":"RpcProcessExitError is raised from the agent_end wait loop when the client has detected the RPC server process closed. The message is str(self._closed_error), the underlying reason the process/reader terminated (non-zero exit, EOF, crash).","triggerScenarios":"Calling wait_for_agent_end (or an API that waits for events) after the omp server subprocess died: crash, kill, OOM, bad binary path, or a server-side unhandled exception closing stdout.","commonSituations":"Server binary killed by a signal (e.g. stop/timeout tests killing the process group), server crashing mid-run, attempting to wait on a client whose process already exited, environment missing the omp executable.","solutions":["Inspect the embedded closed_error/stderr to find why the server process exited","Check server stderr (client.stderr) for a traceback or OOM/kill message","Wrap waits in try/except RpcProcessExitError and restart the client before retrying","Verify the server binary/version is compatible and not being killed by your test harness (e.g. process-group kills)"],"exampleFix":"try:\n    events = client.wait_for_agent_end(timeout=120)\nexcept RpcProcessExitError as exc:\n    print(\"server died:\", exc, \"stderr:\", client.stderr)\n    client = make_client(...)  # restart before retrying","handlingStrategy":"try-catch","validationCode":"if client.poll() is not None:  # process already exited\n    client = restart_client()","typeGuard":null,"tryCatchPattern":"try:\n    events = client.wait_for_agent_end(timeout=120)\nexcept RpcProcessExitError as exc:\n    log.error(\"server exited: %s; stderr=%s\", exc, client.stderr)\n    client = make_client(...)  # recreate before retrying","preventionTips":["Check client.stderr after any failure for the server's exit reason","Don't kill the server's process group in test teardowns while waits are pending","Supervise the subprocess health before long waits"],"tags":["rpc","process-exit","subprocess","ipc"],"backgroundTag":"child-process-exited","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}