paperclipai/paperclip · error · HarnessCapabilityUnavailableError

run.result.proposed

run.result.proposed

Error message

the event consumer must drain provider events before a semantic result can be accepted

What it means

CodexAcpxSession proposes a semantic result via the run.result.proposed event; the #emit helper returns false when no consumer is attached/draining the event stream. Because a proposed result must be observed by the harness consumer to be accepted durably, the session throws HarnessCapabilityUnavailableError with code run.result.proposed, signaling the consumer side is not keeping up or not attached.

Source

Thrown at packages/paperclip-runner/src/drivers/acpx/codex-acpx-driver.ts:1064

      }
      const claimsLaterTurn =
        this.#semanticFingerprint === fingerprint &&
        this.#semanticTurnId !== turnId;
      const repeatsPendingTransfer =
        claimsLaterTurn &&
        this.#pendingSemanticTransfer?.fingerprint === fingerprint &&
        this.#pendingSemanticTransfer.turnId === turnId;
      if (
        this.#semanticFingerprint === null ||
        (claimsLaterTurn && !repeatsPendingTransfer)
      ) {
        if (
          !this.#emit("run.result.proposed", validation.result, {
            turnId,
            itemId: call.callId,
          })
        ) {
          throw new HarnessCapabilityUnavailableError(
            "run.result.proposed",
            "the event consumer must drain provider events before a semantic result can be accepted",
          );
        }
        if (claimsLaterTurn) {
          // A reaffirming retry does not own the durable result until its
          // provider turn completes successfully. A failed or interrupted
          // retry must leave the last completed owner recoverable.
          this.#pendingSemanticTransfer = {
            result: structuredClone(validation.result),
            fingerprint,
            callId: call.callId,
            turnId,
          };
        } else {
          this.#semanticResult = structuredClone(validation.result);
          this.#semanticFingerprint = fingerprint;
          this.#semanticCallId = call.callId;

View on GitHub (pinned to 01ad858492)

Solutions

  1. Attach and continuously drain the session's event stream before issuing turns so run.result.proposed is always consumed.
  2. Fix consumer backpressure (increase queue capacity or drain faster) if emit fails intermittently under load.
  3. Keep the consumer alive until terminal turn settlement; do not tear down mid-turn.
  4. Retry the turn after reconnecting the consumer if the error was transient.

Example fix

// before
const session = await driver.openSession();
await session.submit(prompt); // no consumer attached
// after
const session = await driver.openSession();
session.events.drain((event) => handleEvent(event)); // consume run.result.proposed etc.
await session.submit(prompt);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!session.hasEventConsumer() || session.consumerBackpressured) {
  throw new Error("attach/drain event consumer before submitting turns");
}

Try / catch

try {
  await session.submit(prompt);
} catch (err) {
  if (err instanceof HarnessCapabilityUnavailableError && err.code === "run.result.proposed") {
    // reconnect/restart the event consumer, then retry the turn
  } else throw err;
}

Prevention

When it happens

Trigger: Emitting run.result.proposed for a validated tool-call result when the event consumer has not subscribed, has detached, or its queue is full/backpressured so #emit returns false.

Common situations: Running a Codex ACPX session without attaching the event drain loop; consumer paused due to backpressure or a slow downstream; closing the consumer before the turn's results are fully delivered.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/b918bce614ad1b3c. Report an issue: GitHub.