paperclipai/paperclip · error
Warm run transition permits only its exact cached attachment
Error message
Warm run transition permits only its exact cached attachment replay.
What it means
During a warm run transition, command replay is deliberately restricted: only the exact cached run.attach command (matching commandId AND canonical JSON payload) associated with the transition may be replayed. Any other command id, command type, or altered payload during the warm transition is rejected to prevent tampering or duplicate attachment with different parameters.
Source
Thrown at packages/paperclip-runner/src/control-plane/durable-prp-control-plane.ts:1830
return ticket;
}
queueCommand(
type: string,
payload: Record<string, unknown> = {},
commandId?: string,
deliverImmediately = false,
): DurableRecoveryCoreCommand {
this.#store.assertWritable();
const transition = this.#store.state.warmTransition;
if (transition && transition.phase !== "activated") {
if (
commandId === transition.command.commandId &&
type === "run.attach" &&
canonicalJson(payload) === canonicalJson(transition.command.payload)
)
return transition.command;
throw new Error(
"Warm run transition permits only its exact cached attachment replay.",
);
}
if (
type === "run.attach" &&
payload.paperclipNextAuthority !== undefined &&
![...this.#connections].some(
(connection) =>
connection.secureChannel !== null &&
connection.warmTransitionVersion === 1 &&
!connection.replayOnly,
)
) {
throw new Error(
"Warm run transition capability is required before attachment.",
);
}
if (View on GitHub (pinned to 01ad858492)
Solutions
- Replay the attach command with byte-identical payload to the one cached on the transition (same key order/content).
- Reuse the original commandId stored on transition.command.
- Defer any modified or new attach commands until after the warm transition completes and the connection exits replay-only mode.
- Compare canonicalJson(payload) with canonicalJson(transition.command.payload) locally before sending.
Example fix
// before
await conn.send({ type: "run.attach", commandId: newId, payload: { ...cachedPayload, extra: true } });
// after
await conn.send({ type: "run.attach", commandId: transition.command.commandId, payload: transition.command.payload }); Defensive patterns
Strategy: validation
Validate before calling
function canReplayAttach(transition, msg) {
return msg.commandId === transition.command.commandId &&
msg.type === "run.attach" &&
canonicalJson(msg.payload) === canonicalJson(transition.command.payload);
}
if (!canReplayAttach(transition, msg)) throw new Error("non-identical attach replay"); Type guard
function isExactCachedReplay(transition, msg) {
return msg.type === "run.attach" && msg.commandId === transition.command.commandId;
} Try / catch
try {
await conn.send(msg);
} catch (err) {
if (err.message.includes("exact cached attachment replay")) {
// resend transition.command verbatim
} else throw err;
} Prevention
- Replay commands by reference (transition.command), never by reconstructed copies.
- Avoid mutating payloads between attempts; JSON round-trips can reorder keys.
- Queue new commands until the warm transition finishes.
When it happens
Trigger: Replaying a run.attach command during a warm transition whose commandId differs from transition.command.commandId, or whose payload does not serialize identically (canonicalJson) to the cached transition.command.payload. Also thrown if a non-run.attach command is issued inside the exact-replay branch.
Common situations: Re-serializing the payload after JSON round-trips that change key order or numeric formatting; retry logic that sends an updated attach payload; sending new commands while a warm transition is in flight instead of after it completes.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- test-drive requires its isolated embedded database. Remove D
- test-drive cannot reuse a data directory configured for an e
- --api-key and --api-key-env are mutually exclusive.
- Unsupported test-drive harness: ${String(harness)}.
- Public replay contains unprojected evidence
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/fa8a047fff977847.
Report an issue: GitHub.