{"record":{"id":"8bb1dc1e60ade28a","repo":"paperclipai/paperclip","slug":"paperclip-runner-tool-idempotency-conflict","errorCode":"paperclip_runner_tool_idempotency_conflict","errorMessage":"paperclip_runner_tool_idempotency_conflict","messagePattern":"paperclip_runner_tool_idempotency_conflict","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/paperclip-runner-tool-authority.ts","lineNumber":819,"sourceCode":"        blockedByIssueIds,\n        blockParentUntilDone: false,\n        createdByAgentId: this.binding.agentId,\n        originKind: \"manual\" as const,\n        originId: durableIdempotencyKey,\n        originRunId: this.binding.runId,\n        originIdentityContextId: identityContextId,\n        continuationIdentityContextId: identityContextId,\n        originFingerprint: inputFingerprint,\n        actorAgentId: this.binding.agentId,\n        actorRunId: this.binding.runId,\n        idempotencyKey: durableIdempotencyKey,\n        onDeduplicated: () => { deduplicated = true; },\n      };\n      const child = conversation\n        ? await issueService(tx).create(this.binding.companyId, createInput)\n        : (await issueService(tx).createChild(this.binding.issueId, createInput)).issue;\n      if (deduplicated && child.originFingerprint !== inputFingerprint) {\n        throw new Error(\"paperclip_runner_tool_idempotency_conflict\");\n      }\n      let childStatus = child.status;\n      let childStatusVersion = child.statusVersion;\n      if (child.status === \"blocked\" && blockedByIssueIds.length > 0) {\n        const readiness = await issueService(tx).getDependencyReadiness(child.id, tx);\n        if (readiness.isDependencyReady) {\n          const readyChild = await issueService(tx).update(child.id, {\n            status: \"todo\",\n            actorAgentId: this.binding.agentId,\n          }, tx);\n          if (readyChild) {\n            childStatus = readyChild.status;\n            childStatusVersion = readyChild.statusVersion;\n          }\n        }\n      }\n      if (!deduplicated) {\n        const activity = await persistActivity(tx, {","sourceCodeStart":801,"sourceCodeEnd":837,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/paperclip-runner-tool-authority.ts#L801-L837","documentation":"Thrown from the create-issue/create-child runner tool path when the issue service reports the write was deduplicated (an existing issue matched the origin fingerprint), but the resulting child's originFingerprint differs from the caller-supplied fingerprint. This indicates the idempotency key collided with a prior, materially different creation — the same key was reused for different inputs.","triggerScenarios":"Reusing an idempotencyKey from a previous create task call while changing the task payload (title/description/blockedBy etc.) so the dedupe layer matches an older record by key but the persisted fingerprint no longer equals the new inputFingerprint.","commonSituations":"Agent frameworks that auto-generate stable keys per logical step but mutate step contents on retry; hand-rolled retry code that caches the key but regenerates the body; template-driven delegation that reuses keys across runs.","solutions":["Generate a fresh, unique idempotencyKey for the new logical creation instead of reusing the old key.","If a retry was intended, resend the exact same input payload (byte-identical after canonicalization) with the same key so dedupe replays the original result.","Inspect the existing child issue found by dedupe to confirm whether the prior creation already covers the intent; if so, adopt it rather than creating another."],"exampleFix":"// before\nawait createTask({ idempotencyKey: key, title: 'New title' }); // key used for 'Old title'\n\n// after: same key => same payload, or new key for new intent\nawait createTask({ idempotencyKey: newIdempotencyKey(), title: 'New title' });","handlingStrategy":"validation","validationCode":"if (!isUuid(key) && key.length > 200) throw new Error('bad idempotencyKey');\n// ensure one key is used for exactly one logical creation and payload","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Derive idempotencyKey from a hash of the canonical payload","Never mutate payload fields between retries with the same key","One key per (tool, logical operation) pair only","Log the key alongside the payload for debugging dedupe mismatches"],"tags":["idempotency","concurrency","runner-tools","issue-creation"],"backgroundTag":"idempotency-key-conflict","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}