{"record":{"id":"32b8fef86f1f6565","repo":"paperclipai/paperclip","slug":"warm-run-transition-template-conflicts-with-its-ex","errorCode":null,"errorMessage":"Warm run transition template conflicts with its exact command.","messagePattern":"Warm run transition template conflicts with its exact command\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/control-plane/durable-prp-control-plane.ts","lineNumber":1655,"sourceCode":"      if (transition.phase === \"awaiting_result\")\n        throw new Error(\"Warm transition result is not yet authenticated.\");\n      if (\n        canonicalJson(identity) !==\n        canonicalJson(transition.receipt.newIdentity)\n      ) {\n        throw new Error(\n          \"Warm run transition target conflicts with its durable receipt.\",\n        );\n      }\n      // The new authenticated peer, not an attach-result observer, owns the\n      // activation boundary. Keep the old credential and command replay lane.\n      if (runAttachTemplate !== undefined) {\n        const { paperclipNextAuthority: _boundary, ...expectedTemplate } =\n          transition.command.payload;\n        if (\n          canonicalJson(runAttachTemplate) !== canonicalJson(expectedTemplate)\n        ) {\n          throw new Error(\n            \"Warm run transition template conflicts with its exact command.\",\n          );\n        }\n        const candidate = structuredClone(this.#store.state);\n        candidate.runAttachTemplate = structuredClone(runAttachTemplate);\n        this.#store.commit(candidate);\n      }\n      return;\n    }\n    if (\n      this.#store.state.commands.some(\n        (command) => command.type === \"run.attach\",\n      )\n    ) {\n      throw new Error(\n        \"Warm run identity rotation requires a durable transition receipt.\",\n      );\n    }","sourceCodeStart":1637,"sourceCodeEnd":1673,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/control-plane/durable-prp-control-plane.ts#L1637-L1673","documentation":"During an in-flight (authenticated) warm transition, rotateRunIdentity() was given a runAttachTemplate that does not byte-for-byte match (canonical JSON) the template embedded in the transition's command payload after removing the paperclipNextAuthority boundary. The transition command is the exact source of truth for the attach template, so a divergent template fails closed.","triggerScenarios":"Calling rotateRunIdentity(identity, runAttachTemplate) while warmTransition exists and its phase is past awaiting_result, but runAttachTemplate differs from transition.command.payload minus paperclipNextAuthority — e.g. extra keys, changed provider field, or a template rebuilt from newer config.","commonSituations":"Config or provider settings changed after the transition command was issued; the caller reconstructs the template instead of cloning the original; middleware injects extra fields into the template; a retry passes a merged/partial template.","solutions":["Pass undefined for runAttachTemplate, or clone the template from transition.command.payload (stripping paperclipNextAuthority) exactly.","Diff canonicalJson(runAttachTemplate) against the expected payload-derived template to find the divergent key.","If the template must change, restart the warm transition with the new command rather than mutating the in-flight one.","Freeze the template object at transition initiation and reuse that reference on every rotation call."],"exampleFix":"// before\nconst { paperclipNextAuthority, ...mine } = transition.command.payload;\ncontrolPlane.rotateRunIdentity(identity, { ...mine, extra: true }); // diverges\n// after\nconst { paperclipNextAuthority: _b, ...expected } = transition.command.payload;\ncontrolPlane.rotateRunIdentity(identity, structuredClone(expected));","handlingStrategy":"validation","validationCode":"const t = store.state.warmTransition;\nif (t && runAttachTemplate !== undefined) {\n  const { paperclipNextAuthority: _b, ...expected } = t.command.payload;\n  if (canonicalJson(runAttachTemplate) !== canonicalJson(expected)) {\n    runAttachTemplate = structuredClone(expected); // conform to command payload\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  controlPlane.rotateRunIdentity(identity, runAttachTemplate);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"Warm run transition template conflicts\")) {\n    const { paperclipNextAuthority: _b, ...expected } = store.state.warmTransition.command.payload;\n    controlPlane.rotateRunIdentity(identity, structuredClone(expected));\n  } else throw err;\n}","preventionTips":["Clone the template from the transition command payload instead of rebuilding it from config.","Freeze the template object at transition initiation and reuse the same reference.","Avoid injecting extra keys (logging metadata, feature flags) into attach templates."],"tags":["state-machine","idempotency","warm-transition","fail-closed"],"backgroundTag":"conflicting-config-options","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}