paperclipai/paperclip · error · Error

sync operation path escapes its confinement root

Error message

sync operation ${label} path escapes its confinement root: ${candidate}

What it means

Host-side complete-mediation guard for native sandbox sync: the path canonicalizes fine but resolves outside every allowed orchestrator-owned root (sourceRoots/targetRoots), so the sync would touch files the orchestrator does not own and is rejected before provider handoff.

Solutions

  1. Keep the sync operation path inside its confinement root; remove traversal segments.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/adapter-utils/src/sandbox-managed-runtime.ts:281 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at packages/adapter-utils/src/sandbox-managed-runtime.ts:311

    .filter(Boolean);
}

/**
 * Bounded backoff before each retry of a saturated Git scan: none before the
 * first attempt, 1 second before the second, 2 seconds before the third. Three
 * total attempts (the first plus these two retries) is a liveness parameter,
 * not a security control — the retry only ever fires for the scheduler's
 * typed saturation code (see {@link isWorkspaceGitScanSaturatedError}).
 */
const REFERENCED_SOURCE_IGNORE_SCAN_RETRY_DELAYS_MS = [1_000, 2_000] as const;

async function delay(ms: number): Promise<void> {
  await new Promise<void>((resolve) => setTimeout(resolve, ms));
}

/**
 * True only when `error` carries the workspace Git scan scheduler's typed
 * saturation code on its `code` property. Matches the code alone, never
 * message text — a message can change wording without changing meaning, and
 * matching text would silently stop retrying (or start retrying the wrong
 * failure) the moment it did.
 */
function isWorkspaceGitScanSaturatedError(error: unknown): boolean {
  return (
    typeof error === "object" &&
    error !== null &&
    "code" in error &&
    (error as { code?: unknown }).code === WORKSPACE_GIT_SCAN_SATURATED_CODE
  );
}

/**
 * Resolve a referenced project's Git-ignored paths ONCE, before any staging
 * site runs. Called once per project (see `execute.ts`); the sandbox lane,
 * the SSH lane, and the content-signature walk all consume this one result,
 * so they can never apply a different exclusion set to the same project.

View on GitHub (pinned to 3f1d897a7c)