paperclipai/paperclip · warning · Error

This exact package was already imported by a completed trans

Error message

This exact package was already imported by a completed transfer. Re-export the package to import it again.

What it means

Thrown by uploadCompanyImportTransfer when the server reports created.alreadyCompleted === true. The server content-addresss transfers; if this exact zip already finished an apply, its spooled parts have been deleted, so the parts cannot be re-uploaded and the apply cannot be re-run. The fix is to produce a fresh package.

Source

Thrown at cli/src/commands/client/company.ts:1163

 * with the transfer id once the server holds every part.
 */
export async function uploadCompanyImportTransfer(
  api: Pick<PaperclipApiClient, "post" | "putRaw">,
  zipBytes: Uint8Array,
  opts: { onProgress?: (progress: ImportTransferUploadProgress) => void } = {},
): Promise<string> {
  const manifest = buildImportTransferManifest(zipBytes);
  const created = await api.post<CompanyImportTransferCreated>(
    `/api/companies${COMPANY_IMPORT_TRANSFERS_ROUTE_PATH}`,
    manifest,
  );
  if (!created) {
    throw new Error("Import transfer declaration returned no data.");
  }
  if (created.alreadyCompleted) {
    // The server keys transfers by content, and this exact zip already
    // finished an apply — its spooled parts are gone, so it cannot re-run.
    throw new Error(
      "This exact package was already imported by a completed transfer. Re-export the package to import it again.",
    );
  }
  const missing = new Set(created.missingParts);
  let uploadedParts = manifest.parts.length - missing.size;
  let uploadedBytes = manifest.parts.reduce(
    (sum, part) => (missing.has(part.index) ? sum : sum + part.byteSize),
    0,
  );
  for (const part of manifest.parts) {
    if (!missing.has(part.index)) continue;
    const offset = part.index * manifest.partSizeBytes;
    const bytes = zipBytes.subarray(offset, offset + part.byteSize);
    let lastError: unknown = null;
    let uploaded = false;
    for (let attempt = 0; attempt < IMPORT_TRANSFER_PART_ATTEMPTS && !uploaded; attempt += 1) {
      try {
        await api.putRaw(

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Re-export the source to produce a new zip (content hash will differ if anything changed) and import that.
  2. If the source is unchanged, the previous import already succeeded — verify the company state instead of re-importing.
  3. Add a tiny non-functional change (a timestamp/manifest entry) to force a different content hash if you truly need to re-run.
  4. Check the import history on the server to confirm the prior apply outcome before re-exporting.

Example fix

# before (reusing stale zip)
paperclipai company import nightly-backup-2024-01-01.zip --yes
# after (fresh export first)
paperclipai company export --company cmp_abc --out fresh.zip
paperclipai company import fresh.zip --yes
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await uploadCompanyImportTransfer(api, zipBytes);
} catch (err) {
  if (err instanceof Error && /already imported by a completed transfer/.test(err.message)) {
    console.warn("Package already imported. Re-export the source to re-run, or verify state on the server.");
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Re-running an import with the exact same zip file (byte-identical) after a previous apply completed. Reusing a cached .zip from an earlier export. A backup routine that re-uploads the same nightly artifact twice. Any idempotent retry of an apply that already succeeded.

Common situations: An operator re-runs a failed-looking import that actually completed. CI uploads the same artifact twice. A user double-clicks the apply button. A scheduled job produces a deterministic zip and runs more than once against the same content.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/8e67a3069cbc9ae9. Report an issue: GitHub.