{"record":{"id":"1a78f007e2082997","repo":"paperclipai/paperclip","slug":"paperclip-runner-file-handoff-existing-binding-invalid","errorCode":"paperclip_runner_file_handoff_existing_binding_invalid","errorMessage":"paperclip_runner_file_handoff_existing_binding_invalid","messagePattern":"paperclip_runner_file_handoff_existing_binding_invalid","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/native-runner-file-handoff.ts","lineNumber":1208,"sourceCode":"      .from(issueComments)\n      .where(\n        and(\n          eq(issueComments.id, existing.commentId),\n          eq(issueComments.companyId, input.binding.companyId),\n          eq(issueComments.issueId, input.binding.issueId),\n          eq(issueComments.authorType, \"agent\"),\n          eq(issueComments.authorAgentId, input.binding.agentId),\n          eq(issueComments.createdByRunId, input.binding.runId),\n          eq(\n            issueComments.body,\n            `Prepared ${verified.title} for this response.`,\n          ),\n          isNull(issueComments.deletedAt),\n        ),\n      )\n      .limit(1);\n    if (!comment) {\n      throw new Error(\"paperclip_runner_file_handoff_existing_binding_invalid\");\n    }\n    return {\n      result: {\n        commandId: `deliverable-prepared:${existing.attachmentId}`,\n        disposition: \"duplicate\",\n        attachmentId: existing.attachmentId,\n        contentPath: `/api/attachments/${existing.attachmentId}/content`,\n        downloadPath: `/api/attachments/${existing.attachmentId}/content?download=1`,\n        stateRevision: statusVersion,\n        entityRefs: [\n          existing.attachmentId,\n          ...(existing.workProductId ? [existing.workProductId] : []),\n          comment.id,\n        ],\n        scheduledWakeIds: [],\n      },\n      rollbackDefinitePreCommitFailure: null,\n    };","sourceCodeStart":1190,"sourceCodeEnd":1226,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/native-runner-file-handoff.ts#L1190-L1226","documentation":"When a duplicate handoff attachment is found bound to a comment, the code re-validates that the bound comment still exists with the exact expected author, run, and body (`Prepared <title> for this response.`) and is not soft-deleted. If the comment row is missing or no longer matches, the pre-existing binding is considered corrupt and this error is thrown instead of returning the duplicate disposition.","triggerScenarios":"The attachment from the same run/filename/hash has a non-null issueCommentId, but the referenced issueComments row is deleted (deletedAt set), was authored by a different agent/run, or its body was edited so it no longer equals the canonical prepared-deliverable message.","commonSituations":"A user or moderation flow edited or soft-deleted the agent's 'Prepared ...' comment; a run retry after partial cleanup where the comment was removed but the attachment kept its commentId; data migrations that rewrote comment bodies; comment author recorded with a different runId due to retry re-binding.","solutions":["Inspect the issueComments row for existing.commentId; if it was soft-deleted or its body changed, restore the canonical body (`Prepared <title> for this response.`) and clear deletedAt, or null out the attachment's issueCommentId so a fresh comment is created.","If the binding is unrecoverable, detach the attachment (set issueCommentId null) and re-run the handoff so it takes the create path.","Check for code paths or admin tools that edit/delete agent comments and exclude comments created by the runner protocol (authorType 'agent', authorizationReason 'paperclip_runner_protocol').","Verify the duplicate-match query filters (authorAgentId, createdByRunId, exact body) against your data; align the stored comment with what the current code generates."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// pre-check the duplicate binding's comment before calling the handoff\nconst [c] = await db.select().from(issueComments).where(and(\n  eq(issueComments.id, existingCommentId),\n  isNull(issueComments.deletedAt),\n  eq(issueComments.authorType, 'agent'),\n  eq(issueComments.createdByRunId, runId),\n));\nif (!c) throw new Error('comment binding invalid; detach attachment before retry');","typeGuard":null,"tryCatchPattern":"try {\n  return await prepareNativeRunnerFileHandoff(input);\n} catch (e) {\n  if (e.message === 'paperclip_runner_file_handoff_existing_binding_invalid') {\n    await db.update(issueAttachments).set({ issueCommentId: null }).where(eq(issueAttachments.id, attachmentId));\n    return prepareNativeRunnerFileHandoff(input); // now takes the create path\n  }\n  throw e;\n}","preventionTips":["Do not edit or soft-delete agent comments created under authorizationReason 'paperclip_runner_protocol'.","If moderation must remove a comment, also null the attachment's issueCommentId in the same transaction.","Keep the canonical 'Prepared <title> for this response.' body format stable across versions.","Alert on attachments whose issueCommentId points to missing/deleted comments."],"tags":["database","idempotency","integrity-check","native-runner"],"backgroundTag":"record-not-found","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"}