paperclipai/paperclip · warning · Error

paperclip_runner_attachment_staging_cleanup_failed

paperclip_runner_attachment_staging_cleanup_failed

Error message

paperclip_runner_attachment_staging_cleanup_failed

What it means

Raised by the cleanup function returned from stageNativeRunnerWakeAttachments when one or more per-attachment cleanup callbacks reject after Promise.allSettled. It signals that staged attachment files could not be fully removed from the workspace staging directory, leaving residue behind.

Solutions

  1. Retry cleanup() after a short delay to let file locks release
  2. Manually remove leftover files under the workspace's private staging directory (the per-process staging subdirectory)
  3. Check filesystem permissions and that the workspace root still exists before rerunning the agent
  4. Inspect logs to identify which attachment cleanup rejected and fix the underlying cause (lock, permission, missing path)

Example fix

// before
await staged.cleanup(); // throws cleanup_failed, residue left
// after
try {
  await staged.cleanup();
} catch (err) {
  if (String(err).includes("paperclip_runner_attachment_staging_cleanup_failed")) {
    await new Promise((r) => setTimeout(r, 250));
    await staged.cleanup().catch(() => log.warn("staging residue remains; scrub on next run"));
  } else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  await staged.cleanup();
} catch (err) {
  if (err instanceof Error && err.message === "paperclip_runner_attachment_staging_cleanup_failed") {
    // schedule retry; residue is scrubbed automatically on the next staging run in this workspace
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the returned cleanup() after staging completes while at least one writeStagedAttachment cleanup fails (e.g. unlink fails because the file is locked, permissions changed, or the workspace directory was removed mid-flight).

Common situations: Antivirus or a file watcher holding the staged file open on Windows; workspace directory deleted while the run was executing; read-only filesystem or permission change on the staging directory; concurrent scrub racing with cleanup.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/41d445f7d613ba60. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/native-runtime/native-runner-file-handoff.ts:1043

        staged.push({
          id: row.id,
          filename: row.filename?.trim() || "attachment",
          contentType: row.contentType,
          byteSize: row.byteSize,
          workspaceRelativePath: null,
          unavailableReason: "attachment_staging_failed",
        });
      }
    }
    return {
      attachments: staged,
      cleanup: async () => {
        try {
          const results = await Promise.allSettled(
            cleanups.map((cleanup) => cleanup()),
          );
          if (results.some((result) => result.status === "rejected")) {
            throw new Error(
              "paperclip_runner_attachment_staging_cleanup_failed",
            );
          }
        } finally {
          releaseActiveStage();
        }
      },
    };
  } catch (error) {
    releaseActiveStage();
    throw error;
  }
}

export function renderNativeRunnerStagedAttachmentPrompt(
  attachments: readonly NativeRunnerStagedAttachment[],
): string {
  if (attachments.length === 0) return "";

View on GitHub (pinned to 3f1d897a7c)