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
- Ensure the package.json physically lives inside the resolved provider root directory (compare realpathSync of both)
- If using symlinked store layouts, select the provider root as the real (realpathSync) directory so canonical root contains the canonical manifest
- Pass the correct matching manifest for the chosen root instead of one from another package/version
- 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
- Realpath both root and manifest before wiring them together
- Avoid symlink-switched install layouts (provider -> provider-vN) that place files outside the selected root
- Copy, don't symlink, package.json when staging provider installs
- Audit provider directories for symlinks escaping the root before registration
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
- ACPX provider node_modules resolves outside the selected pro
- ACPX ${agent} runtime executable must be a real regular file
- Access denied
- Trusted viewer must not use symlinks
- ACPX provider package root must be an explicit normalized ab
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/17cd9b1f855453a5.
Report an issue: GitHub.