can1357/oh-my-pi · error · RpcConcurrencyError

Cannot start {operation} while {self.active_operation} is al

Error message

Cannot start {operation} while {self.active_operation} is already collecting prompt lifecycle events

What it means

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.

Source

Thrown at python/omp-rpc/src/omp_rpc/client.py:430

    def current_index(self) -> int:
        return self.offset + len(self.items)

    def snapshot(self) -> tuple[THistoryItem, ...]:
        return tuple(self.items)

    def snapshot_from(self, start_index: int) -> tuple[THistoryItem, ...]:
        return tuple(self.items[start_index - self.offset :])


@dataclass(slots=True)
class _PromptLifecycleCoordinator:
    lock: threading.Lock = field(default_factory=threading.Lock)
    active_operation: str | None = None

    def acquire(self, operation: str) -> None:
        with self.lock:
            if self.active_operation is not None:
                raise RpcConcurrencyError(
                    f"Cannot start {operation} while {self.active_operation} is already collecting prompt lifecycle events"
                )
            self.active_operation = operation

    def release(self, operation: str) -> None:
        with self.lock:
            if self.active_operation == operation:
                self.active_operation = None


class RpcClient:
    def __init__(
        self,
        *,
        command: Sequence[str] | None = None,
        executable: str = "omp",
        provider: str | None = None,
        model: str | None = None,

View on GitHub (pinned to 9690622007)

Solutions

  1. Await/complete the first prompt before starting the next on the same client.
  2. Create a separate RpcClient (separate agent subprocess) per concurrent operation.
  3. Serialize prompts with an asyncio.Lock or queue around client.prompt() calls.
  4. Check for un-awaited coroutines or background tasks issuing prompts concurrently.

Example fix

# before: concurrent prompts on one client
tasks = [client.prompt(t) for t in prompts]
results = await asyncio.gather(*tasks)

# after: serialize, or one client per prompt
results = []
for t in prompts:
    results.append(await client.prompt(t))
Defensive patterns

Strategy: try-catch

Try / catch

prompt_lock = threading.Lock()
with prompt_lock:
    result = client.prompt(text)  # serialize lifecycle-collecting ops
# or:
try:
    result = await client.prompt(text)
except RpcConcurrencyError as exc:
    logger.error("another prompt is active on this client: %s", exc)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/7059ad5d7267de5a. Report an issue: GitHub.