{"record":{"id":"38f663ba9f4749e5","repo":"can1357/oh-my-pi","slug":"rpc-client-is-already-started","errorCode":null,"errorMessage":"RPC client is already started","messagePattern":"RPC client is already started","errorType":"exception","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":577,"sourceCode":"            return \"\".join(self._stderr_chunks.snapshot())\n\n    @property\n    def command(self) -> tuple[str, ...]:\n        return self._build_command()\n\n    @property\n    def protocol_errors(self) -> tuple[RpcProtocolError, ...]:\n        with self._state_lock:\n            return self._protocol_errors.snapshot()\n\n    @property\n    def listener_errors(self) -> tuple[ListenerErrorEvent, ...]:\n        with self._state_lock:\n            return self._listener_errors.snapshot()\n\n    def start(self) -> RpcClient:\n        if self._process is not None:\n            raise RpcError(\"RPC client is already started\")\n\n        self._ready.clear()\n        self._stopping = False\n        self._closed_error = None\n        self._ready_received = False\n        self._ready_event = None\n        self._protocol_version = 1\n        self._protocol_v2_enabled = False\n        self._frame_decoder = _RpcFrameDecoder()\n        self._events.clear()\n        self._async_errors.clear()\n        self._scheduled_agent_runs = 0\n        self._completed_agent_runs = 0\n        self._last_schedule_async_error_index = 0\n        self._ui_requests = queue.Queue()\n        with self._state_lock:\n            self._stderr_chunks.clear()\n        with self._state_lock:","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L559-L595","documentation":"start() spawns the agent subprocess and initializes transport state; it refuses to run twice on the same RpcClient instance. If self._process is already set (client previously started and not stopped), this RpcError is raised.","triggerScenarios":"Calling client.start() twice without an intervening stop(), e.g. retry logic re-invoking start after startup, or shared initialization code running start on an already-started client.","commonSituations":"Idempotency guards missing around init; restart logic calling start() instead of stop()-then-start(); multiple modules each calling start() on a shared singleton client.","solutions":["Guard calls: only call start() if the client is not already running (track your own started flag or check process state if exposed).","Wrap start() in try/except RpcError and treat 'already started' as success for idempotent initialization.","For restarts, call stop() before start().","Ensure only one code path owns the client lifecycle (centralize start/stop)."],"exampleFix":"# before\nclient.start()  # may run twice\n\n# after\ntry:\n    client.start()\nexcept RpcError as exc:\n    if \"already started\" not in str(exc):\n        raise  # already running: safe to continue","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    client.start()\nexcept RpcError as exc:\n    if \"already started\" not in str(exc):\n        raise  # idempotent start: safe to continue","preventionTips":["Centralize client lifecycle in one owner module","Track your own started flag for idempotent init","Call stop() before start() when restarting"],"tags":["rpc","client-lifecycle","client-misuse","state-error"],"backgroundTag":"client-already-started","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}