{"record":{"id":"7059ad5d7267de5a","repo":"can1357/oh-my-pi","slug":"cannot-start-operation-while-self-active-operat","errorCode":null,"errorMessage":"Cannot start {operation} while {self.active_operation} is already collecting prompt lifecycle events","messagePattern":"Cannot start (.+?) while (.+?) is already collecting prompt lifecycle events","errorType":"exception","errorClass":"RpcConcurrencyError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":430,"sourceCode":"    def current_index(self) -> int:\n        return self.offset + len(self.items)\n\n    def snapshot(self) -> tuple[THistoryItem, ...]:\n        return tuple(self.items)\n\n    def snapshot_from(self, start_index: int) -> tuple[THistoryItem, ...]:\n        return tuple(self.items[start_index - self.offset :])\n\n\n@dataclass(slots=True)\nclass _PromptLifecycleCoordinator:\n    lock: threading.Lock = field(default_factory=threading.Lock)\n    active_operation: str | None = None\n\n    def acquire(self, operation: str) -> None:\n        with self.lock:\n            if self.active_operation is not None:\n                raise RpcConcurrencyError(\n                    f\"Cannot start {operation} while {self.active_operation} is already collecting prompt lifecycle events\"\n                )\n            self.active_operation = operation\n\n    def release(self, operation: str) -> None:\n        with self.lock:\n            if self.active_operation == operation:\n                self.active_operation = None\n\n\nclass RpcClient:\n    def __init__(\n        self,\n        *,\n        command: Sequence[str] | None = None,\n        executable: str = \"omp\",\n        provider: str | None = None,\n        model: str | None = None,","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L412-L448","documentation":"The client serializes prompt lifecycle event collection: a per-client guard ensures only one operation at a time collects events. acquire() raises RpcConcurrencyError if you start a second operation (e.g. a second prompt) while the first is still active.","triggerScenarios":"Calling client.prompt() (or another lifecycle-collecting operation) while a previous prompt is still running on the same RpcClient instance — e.g. concurrent tasks sharing one client, or not awaiting the first prompt before starting another.","commonSituations":"Asyncio tasks or threads sharing a single RpcClient; fire-and-forget prompts without await; retry logic that issues a new prompt while the old one is still completing.","solutions":["Await/complete the first prompt before starting the next on the same client.","Create a separate RpcClient (separate agent subprocess) per concurrent operation.","Serialize prompts with an asyncio.Lock or queue around client.prompt() calls.","Check for un-awaited coroutines or background tasks issuing prompts concurrently."],"exampleFix":"# before: concurrent prompts on one client\ntasks = [client.prompt(t) for t in prompts]\nresults = await asyncio.gather(*tasks)\n\n# after: serialize, or one client per prompt\nresults = []\nfor t in prompts:\n    results.append(await client.prompt(t))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"prompt_lock = threading.Lock()\nwith prompt_lock:\n    result = client.prompt(text)  # serialize lifecycle-collecting ops\n# or:\ntry:\n    result = await client.prompt(text)\nexcept RpcConcurrencyError as exc:\n    logger.error(\"another prompt is active on this client: %s\", exc)","preventionTips":["Never share one RpcClient across concurrent tasks/threads","Await each prompt before starting the next","Use one client per concurrent operation or a locking queue"],"tags":["rpc","concurrency","client-misuse","lifecycle"],"backgroundTag":"concurrent-operation-not-allowed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}