paperclipai/paperclip · error · Error
paperclip_runner_tool_idempotency_conflict
paperclip_runner_tool_idempotency_conflict
Error message
paperclip_runner_tool_idempotency_conflict
What it means
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.
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.
Example fix
// before
await createTask({ idempotencyKey: key, title: 'New title' }); // key used for 'Old title'
// after: same key => same payload, or new key for new intent
await createTask({ idempotencyKey: newIdempotencyKey(), title: 'New title' }); Defensive patterns
Strategy: validation
Validate before calling
if (!isUuid(key) && key.length > 200) throw new Error('bad idempotencyKey');
// ensure one key is used for exactly one logical creation and payload Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- A different semantic result was already committed
- ACPX provider ownership admission is closed
- ACPX runtime host already has an active turn
- Bridge envelope changed while reading.
- Bridge host response body capacity is busy.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/8bb1dc1e60ade28a.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/native-runtime/paperclip-runner-tool-authority.ts:819
blockedByIssueIds,
blockParentUntilDone: false,
createdByAgentId: this.binding.agentId,
originKind: "manual" as const,
originId: durableIdempotencyKey,
originRunId: this.binding.runId,
originIdentityContextId: identityContextId,
continuationIdentityContextId: identityContextId,
originFingerprint: inputFingerprint,
actorAgentId: this.binding.agentId,
actorRunId: this.binding.runId,
idempotencyKey: durableIdempotencyKey,
onDeduplicated: () => { deduplicated = true; },
};
const child = conversation
? await issueService(tx).create(this.binding.companyId, createInput)
: (await issueService(tx).createChild(this.binding.issueId, createInput)).issue;
if (deduplicated && child.originFingerprint !== inputFingerprint) {
throw new Error("paperclip_runner_tool_idempotency_conflict");
}
let childStatus = child.status;
let childStatusVersion = child.statusVersion;
if (child.status === "blocked" && blockedByIssueIds.length > 0) {
const readiness = await issueService(tx).getDependencyReadiness(child.id, tx);
if (readiness.isDependencyReady) {
const readyChild = await issueService(tx).update(child.id, {
status: "todo",
actorAgentId: this.binding.agentId,
}, tx);
if (readyChild) {
childStatus = readyChild.status;
childStatusVersion = readyChild.statusVersion;
}
}
}
if (!deduplicated) {
const activity = await persistActivity(tx, {View on GitHub (pinned to 3f1d897a7c)