paperclipai/paperclip · warning

Skipped ${applied.skippedMissingAttachmentObjects} attachmen

Error message

Skipped ${applied.skippedMissingAttachmentObjects} attachments whose source files were missing from storage.

What it means

After a confirmed worktree import, applyMergePlan inserted rows into the target; attachments whose database rows were planned but whose backing object files were absent from source storage were skipped and counted in skippedMissingAttachmentObjects. The import still completes — only those attachment payloads are missing in the target.

Source

Thrown at cli/src/commands/worktree.ts:4232

      ? true
      : await p.confirm({
        message: `Import ${collected.plan.counts.issuesToInsert} issues and ${collected.plan.counts.commentsToInsert} comments from ${sourceEndpoint.label} into ${targetEndpoint.label}?`,
        initialValue: false,
      });
    if (p.isCancel(confirmed) || !confirmed) {
      p.log.warn("Import cancelled.");
      return;
    }

    const applied = await applyMergePlan({
      sourceStorages,
      targetStorage,
      targetDb: targetHandle.db,
      company,
      plan: collected.plan,
    });
    if (applied.skippedMissingAttachmentObjects > 0) {
      p.log.warn(
        `Skipped ${applied.skippedMissingAttachmentObjects} attachments whose source files were missing from storage.`,
      );
    }
    p.outro(
      pc.green(
        `Imported ${applied.insertedProjects} projects (${applied.insertedProjectWorkspaces} workspaces), ${applied.insertedIssues} issues, ${applied.insertedComments} comments, ${applied.insertedDocuments} documents (${applied.insertedDocumentRevisions} revisions, ${applied.mergedDocuments} merged), and ${applied.insertedAttachments} attachments into ${company.issuePrefix}.`,
      ),
    );
  } finally {
    await targetHandle.stop();
    await sourceHandle.stop();
  }
}

async function backupWorktreeReseedTarget(input: {
  targetConfig: PaperclipConfig;
  targetPaths: WorktreeLocalPaths;
}): Promise<string> {

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Verify the source instance's storage settings (storage mode, local dir, S3 bucket) — the import reads objects from the configured source storage.
  2. Restore or copy the missing object files back into source storage (attachment rows are already in the source DB).
  3. Re-run `paperclipai worktree import` — already-inserted rows are handled by the plan; the previously skipped attachments import once their files exist.
  4. If the count equals ALL attachments, the source storage config is almost certainly wrong — fix that first.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: every planned attachment object must exist in source storage
const missing: string[] = [];
for (const att of plan.attachments) {
  const exists = await sourceStorage.exists(att.storageKey);
  if (!exists) missing.push(att.storageKey);
}
if (missing.length) {
  console.error(`Source storage is missing ${missing.length} attachment objects; fix storage before import.`);
}

Prevention

When it happens

Trigger: Source storage (local disk dir or S3 backend) missing object files for attachment rows: objects deleted out-of-band, source storage config pointing at the wrong location/bucket, partial copy of a data dir, S3 permission errors surfaced as missing keys.

Common situations: Copying a Paperclip data directory but forgetting the storage/uploads dir; S3 lifecycle rules deleting old objects; moving machines with an incomplete rsync.

Related errors


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-18). Data as JSON: /api/errors/7e2b676fa496510d. Report an issue: GitHub.