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

  1. Inspect the preserved file in the workspace and call register_deliverable again to verify its current filename, size, and SHA-256
  2. Cite the NEW deliverable:<attachmentId> from the fresh receipt in the completion report
  3. 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

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


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)