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
- Attach and continuously drain the session's event stream before issuing turns so run.result.proposed is always consumed.
- Fix consumer backpressure (increase queue capacity or drain faster) if emit fails intermittently under load.
- Keep the consumer alive until terminal turn settlement; do not tear down mid-turn.
- 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
- Always attach the event drain loop before submitting turns.
- Keep consuming until terminal settlement; never close consumers mid-turn.
- Monitor consumer queue depth to prevent backpressure-induced emit failure.
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
- persisted Codex ACPX session identity is inconsistent
- persisted Codex ACPX resultless recovery requires a complete
- ACPX_SESSION_ENSURE_NON_ERROR
- ACPX provider identity is incomplete
- pending-retry store full (bound=${bound}); evicted oldest ba
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/b918bce614ad1b3c.
Report an issue: GitHub.