{"record":{"id":"6eb5383bd17dfd43","repo":"paperclipai/paperclip","slug":"durable-prp-run-attachment-template-is-invalid","errorCode":null,"errorMessage":"Durable PRP run attachment template is invalid.","messagePattern":"Durable PRP run attachment template is invalid\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/control-plane/durable-prp-control-plane.ts","lineNumber":1713,"sourceCode":"      runAttachTemplate:\n        runAttachTemplate === undefined\n          ? null\n          : structuredClone(runAttachTemplate),\n    });\n    this.#identity = structuredClone(identity);\n    this.#store.save();\n  }\n\n  /**\n   * Retain the connection-free provider preparation payload before the first\n   * runner bootstrap. Completed command history is bounded and may be\n   * compacted before a warm continuation arrives, so it cannot be the sole\n   * source for a later run.attach. Repeating the same write is idempotent;\n   * changing an established seed fails closed.\n   */\n  persistRunAttachTemplate(runAttachTemplate: Record<string, unknown>): void {\n    if (!isRecord(runAttachTemplate.provider)) {\n      throw new Error(\"Durable PRP run attachment template is invalid.\");\n    }\n    const existing = this.#store.state.runAttachTemplate;\n    if (\n      existing !== undefined &&\n      existing !== null &&\n      canonicalJson(existing) !== canonicalJson(runAttachTemplate)\n    ) {\n      throw new Error(\"Durable PRP run attachment template conflicts.\");\n    }\n    if (existing !== undefined && existing !== null) return;\n    this.#store.state.runAttachTemplate = structuredClone(runAttachTemplate);\n    this.#store.save();\n  }\n\n  issueBootstrapTicket(ttlMs = 5_000): string {\n    this.#store.assertWritable();\n    if (this.#store.state.warmTransition) {\n      throw new Error(","sourceCodeStart":1695,"sourceCodeEnd":1731,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/control-plane/durable-prp-control-plane.ts#L1695-L1731","documentation":"persistRunAttachTemplate() requires its argument to be an object with a truthy `provider` field (checked via isRecord(runAttachTemplate.provider)). The template is the provider preparation payload reused for run.attach after restart, so a template without a valid provider record cannot be persisted and the call fails immediately.","triggerScenarios":"Calling persistRunAttachTemplate() with null/undefined coerced in, an object missing the provider key, provider set to a non-object (string, number, boolean), or provider explicitly null.","commonSituations":"Config loading produced a partial template (provider section absent); a caller passes the wrong variable; JSON round-trip dropped or renamed the provider field; template built dynamically with an optional provider that was skipped.","solutions":["Ensure the template includes a valid provider object, e.g. { provider: { ... }, ... }, before calling persistRunAttachTemplate.","Validate the template shape at construction time (check typeof template.provider === \"object\" && template.provider !== null).","Trace where the template is built; fix the config/source that omitted the provider section.","If the template legitimately has no provider, this API is the wrong entry point — review the intended flow."],"exampleFix":"// before\ncontrolPlane.persistRunAttachTemplate({ model: \"opus\" }); // no provider\n// after\ncontrolPlane.persistRunAttachTemplate({ provider: { name: \"anthropic\" }, model: \"opus\" });","handlingStrategy":"validation","validationCode":"function isValidAttachTemplate(t: unknown): t is Record<string, unknown> & { provider: Record<string, unknown> } {\n  return typeof t === \"object\" && t !== null && typeof (t as any).provider === \"object\" && (t as any).provider !== null;\n}\nif (!isValidAttachTemplate(template)) throw new Error(\"attach template requires a provider object\");","typeGuard":"function hasProvider(t: unknown): t is { provider: Record<string, unknown> } {\n  return typeof t === \"object\" && t !== null && \"provider\" in t && typeof (t as { provider: unknown }).provider === \"object\" && (t as { provider: unknown }).provider !== null;\n}","tryCatchPattern":"try {\n  controlPlane.persistRunAttachTemplate(template);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"run attachment template is invalid\")) {\n    throw new Error(`attach template missing provider: ${JSON.stringify(template)}`);\n  } else throw err;\n}","preventionTips":["Validate template shape (provider object present) at the point the template is built.","Guard config loading so a missing provider section fails at startup, not at persist time.","Type the template as { provider: ... } & Record<string, unknown> in caller code so TS catches omissions."],"tags":["validation","schema","fail-closed"],"backgroundTag":"schema-validation-failed","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"}