paperclipai/paperclip · error
This attachment has no matching verified publication…
Error message
This attachment has no matching verified publication receipt for this run's requested output. Inspect any preserved file and use register_deliverable to verify its current filename, size, and SHA-256, then cite the new receipt. No human completion approval was created.
What it means
A cited attachment exists on the task, but for a newly requested file output the runtime also requires a current publication receipt matching that attachment's filename, byte size, and SHA-256 (hasCurrentPublicationReceipt) originating from this run. Prior-run or user-uploaded bytes are explicitly not proof that this run published the requested output, so the evidence is rejected.
Solutions
- Inspect the preserved file in the workspace and call register_deliverable again to verify its current filename, size, and SHA-256
- Cite the NEW deliverable:<attachmentId> from the fresh receipt in the completion report
- If the original bytes are gone, regenerate the output, register it, and cite that receipt
Example fix
// before Deliverable: deliverable:<attachment-from-prior-run> // after register_deliverable(file) -> receipt -> "Deliverable: deliverable:<new-attachment-id>"
Defensive patterns
Strategy: validation
Validate before calling
const receiptOk = receipts.some(r => r.attachmentId === citedId && r.originatingRunId === currentRunId && r.sha256 === currentFileSha256); if (!receiptOk) await registerDeliverable(file); // re-verify and cite the new receipt
Type guard
const currentRunReceipt = (r, runId) => r.originatingRunId === runId && r.sha256 != null;
Try / catch
try { await feedback(payload); } catch (e) { if (e.message.includes("no matching verified publication receipt")) { await registerDeliverable(file); /* update citation to new receipt */ } else throw e; } Prevention
- After any file regeneration, re-run register_deliverable — old receipts are invalidated by changed bytes
- Only cite attachments produced by the current run, not prior runs or user uploads
- Store the sha256 from your own register_deliverable call to self-verify before citing
When it happens
Trigger: validateNativeDeliverableEvidence with fileRequested=true and an attachment whose originatingRunId !== binding.runId (skipped via continue, leaving no registeredAttachment), or whose stored bytes no longer match a receipt from this run (filename/size/sha256 changed).
Common situations: Citing an attachment produced by an earlier run or uploaded by the user; workspace file was regenerated with different bytes after register_deliverable; controller restart cleared receipts so re-verification is needed.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- ACPX runtime executable digest mismatch
- ACPX private snapshot digest mismatch
- ACPX snapshot manifest digest mismatch
- Artifact bytes do not match their immutable pin.
- Completion cites a workspace-only file that the user cannot…
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/2cd2b9ceb7f56b0c.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/native-runtime/native-deliverable-feedback.ts:124
const id = attachmentPath?.[1] ?? ref.slice("deliverable:".length);
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
const [attachment] = uuid.test(id)
? await db.select({ id: issueAttachments.id, originatingRunId: issueAttachments.originatingRunId,
filename: assets.originalFilename, byteSize: assets.byteSize, sha256: assets.sha256 }).from(issueAttachments)
.innerJoin(assets, and(eq(assets.id, issueAttachments.assetId), eq(assets.companyId, binding.companyId)))
.where(and(eq(issueAttachments.id, id), eq(issueAttachments.companyId, binding.companyId), eq(issueAttachments.issueId, binding.issueId)))
.limit(1)
: [];
if (!attachment) {
throw new Error("Completion cites no registered attachment on this task. Use register_deliverable for the requested file and cite deliverable:<attachmentId> from its receipt. No human completion approval was created.");
}
// A prior output (or user input) can be useful context, but does not prove
// this run published the newly requested output. The receipt survives a
// controller restart of this run; a replacement can re-register preserved
// workspace bytes internally rather than asking the user to confirm them.
if (fileRequested && attachment.originatingRunId !== binding.runId) continue;
if (fileRequested && !await hasCurrentPublicationReceipt(db, binding.companyId, binding.semanticToolReceipts, attachment)) {
throw new Error("This attachment has no matching verified publication receipt for this run's requested output. Inspect any preserved file and use register_deliverable to verify its current filename, size, and SHA-256, then cite the new receipt. No human completion approval was created.");
}
registeredAttachment = true;
continue;
}
// URLs and typed durable refs are not workspace paths. Verification commands
// belong in verification; do not scan prose or upload files named by a model.
const localFile = /^(?:file:|\.{0,2}\/|[a-z]:[\\/])/iu.test(ref)
|| (!/^[a-z][a-z0-9+.-]*:/iu.test(ref) && /^[^\r\n]+\.[a-z0-9]{1,16}(?::\d+(?::\d+)?)?$/iu.test(ref));
if (localFile && (fileRequested || artifactRefs.has(value))) {
throw new Error("Completion cites a workspace-only file that the user cannot download. Before finishing, use register_deliverable for requested file outputs and cite deliverable:<attachmentId> from the receipt, with /api/attachments/<attachmentId>/content as the download link. For repository changes, cite an accessible PR or registered work product instead. No human completion approval was created.");
}
}
if (fileRequested && !registeredAttachment) {
const products = refs.size ? await db.select().from(issueWorkProducts).where(and(
eq(issueWorkProducts.companyId, binding.companyId), eq(issueWorkProducts.issueId, binding.issueId),
)) : [];
const accessibleProduct = products.some(product => {
if (product.createdByRunId !== binding.runId) return false;View on GitHub (pinned to 3f1d897a7c)