paperclipai/paperclip · error

ACPX provider package manifest resolves outside the selected

Error message

ACPX provider package manifest resolves outside the selected provider root

What it means

After validating that root and manifest are normalized absolute paths, the resolver canonicalizes both with realpathSync and requires the canonical manifest to live inside the canonical root (pathIsInside). If the package.json resolves (through symlinks) to a location outside the provider root directory, the provider layout is considered tampered with or misconfigured and resolution is refused.

Source

Thrown at packages/paperclip-runner/src/drivers/acpx/installation-integrity.ts:315

    );
  }
  const manifest = (
    providerPackageManifest ?? resolve(root, "package.json")
  ).trim();
  if (
    !manifest ||
    !isAbsolute(manifest) ||
    manifest.includes("\0") ||
    resolve(manifest) !== manifest
  ) {
    throw new Error(
      "ACPX provider package manifest must be an explicit normalized absolute path",
    );
  }
  const canonicalRoot = realpathSync(root);
  const canonicalManifest = realpathSync(manifest);
  if (!pathIsInside(canonicalRoot, canonicalManifest)) {
    throw new Error(
      "ACPX provider package manifest resolves outside the selected provider root",
    );
  }
  const canonicalNodeModules = realpathSync(
    resolve(canonicalRoot, "node_modules"),
  );
  if (!pathIsInside(canonicalRoot, canonicalNodeModules)) {
    throw new Error(
      "ACPX provider node_modules resolves outside the selected provider root",
    );
  }
  return (packageName, issuerPackageJsonPath) => {
    const canonicalIssuer =
      issuerPackageJsonPath === undefined
        ? canonicalManifest
        : realpathSync(issuerPackageJsonPath);
    if (!pathIsInside(canonicalRoot, canonicalIssuer)) {
      throw new Error(

View on GitHub (pinned to 01ad858492)

Solutions

  1. Ensure the package.json physically lives inside the resolved provider root directory (compare realpathSync of both)
  2. If using symlinked store layouts, select the provider root as the real (realpathSync) directory so canonical root contains the canonical manifest
  3. Pass the correct matching manifest for the chosen root instead of one from another package/version
  4. Update the layout so root and manifest share the same realpath ancestor, or remove symlink indirection from the provider install

Example fix

// before
createAcpxPackageJsonResolver('/opt/acpx/provider', '/opt/acpx/other/package.json');
// after
const canonicalRoot = fs.realpathSync('/opt/acpx/provider');
createAcpxPackageJsonResolver(canonicalRoot, path.join(canonicalRoot, 'package.json'));
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import path from 'node:path';
function manifestInsideRoot(root: string, manifest: string): boolean {
  const canonicalRoot = fs.realpathSync(root);
  const canonicalManifest = fs.realpathSync(manifest);
  return canonicalManifest.startsWith(canonicalRoot + path.sep);
}

Try / catch

try {
  const resolver = createAcpxPackageJsonResolver(root, manifest);
} catch (err) {
  if (err instanceof Error && /manifest resolves outside the selected provider root/.test(err.message)) {
    const cr = fs.realpathSync(root), cm = fs.realpathSync(manifest);
    throw new Error(`Provider layout mismatch: manifest realpath ${cm} is outside root realpath ${cr}; fix symlinks or pass the matching manifest`);
  }
  throw err;
}

Prevention

When it happens

Trigger: root is a symlink whose target's manifest itself symlinks (or realpath-resolves) outside the root, e.g. root=/opt/provider -> /opt/provider-v2 while the manifest points into a shared cache; passing a manifest from a different package than root.

Common situations: pnpm/yarn store layouts where package files are symlinked from a central store outside the provider directory; a user copied a package.json from another project to a path outside root; version-switching symlinks that point the manifest outside the selected root.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/17cd9b1f855453a5. Report an issue: GitHub.