paperclipai/paperclip · error
ACPX provider package issuer for ${packageName} resolves out
Error message
ACPX provider package issuer for ${packageName} resolves outside the selected provider root What it means
createAcpxPackageJsonResolver returns a resolver closure that, for each requested package, canonicalizes the issuer package.json path via realpathSync and verifies it lives inside the selected provider root. This error is thrown when the issuer manifest (explicitly passed, or defaulting to the provider root manifest) canonicalizes to a path outside canonicalRoot, typically via symlinks. It is a fail-closed containment check ensuring dependency resolution never anchors outside the verified provider installation.
Source
Thrown at packages/paperclip-runner/src/drivers/acpx/installation-integrity.ts:333
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(
`ACPX provider package issuer for ${packageName} resolves outside the selected provider root`,
);
}
const packageJsonPath = realpathSync(
resolvePackageJsonFromIssuer(packageName, canonicalIssuer),
);
if (!pathIsInside(canonicalNodeModules, packageJsonPath)) {
throw new Error(
`ACPX provider package ${packageName} resolves outside the selected provider root`,
);
}
return packageJsonPath;
};
}
function resolvePackageJsonFromIssuer(
packageName: string,
issuerPackageJsonPath: string,View on GitHub (pinned to 01ad858492)
Solutions
- Inspect the issuerPackageJsonPath with `realpathSync` and confirm it is inside the provider root passed to createAcpxPackageJsonResolver; if not, pass the correct issuer or correct provider root.
- If the issuer is a symlink into a store outside the root, either relocate the installation so symlinks stay inside the root, or pass the in-root manifest path explicitly instead of relying on the default.
- Recreate the provider root (clean install of the ACPX provider packages) so realpath of the manifest lands inside it.
- Verify the root argument is the canonical (realpath) root, not a path whose realpath differs (e.g. macOS /var vs /private/var).
Example fix
// before const resolver = createAcpxPackageJsonResolver(providerRoot); resolver(pkg, "/opt/other-store/pkg/package.json"); // outside providerRoot // after const issuer = resolve(providerRoot, "node_modules/pkg/package.json"); const resolver = createAcpxPackageJsonResolver(realpathSync(providerRoot)); resolver(pkg, issuer); // issuer realpath stays inside canonicalRoot
Defensive patterns
Strategy: validation
Validate before calling
import { realpathSync } from "node:fs";
import { relative, isAbsolute } from "node:path";
function isInside(root: string, candidate: string): boolean {
const r = relative(realpathSync(root), realpathSync(candidate));
return r !== "" && !r.startsWith("..") && !isAbsolute(r);
}
if (!isInside(providerRoot, issuerPath)) throw new Error("issuer outside provider root"); Type guard
function issuerInsideRoot(providerRoot: string, issuerPath?: string): boolean {
if (issuerPath === undefined) return true;
try { return isInside(providerRoot, issuerPath); } catch { return false; }
} Try / catch
try {
const manifestPath = resolver(packageName, issuerPath);
} catch (err) {
if (err instanceof Error && err.message.includes("issuer") && err.message.includes("outside the selected provider root")) {
// re-anchor issuer inside provider root or rebuild provider installation
} else throw err;
} Prevention
- Always pass issuer manifests that live inside the provider root; prefer the default (root manifest) when unsure.
- Canonicalize both root and issuer with realpathSync before validating containment yourself.
- Avoid installations that symlink package dirs to a store outside the root (e.g. shared pnpm stores).
- Log realpathSync(issuer) alongside the configured root when wiring profiles to catch drift early.
When it happens
Trigger: Calling the resolver (or defaultPackageJsonResolver) with an issuerPackageJsonPath that is a symlink into another location, points to a package outside providerPackageRoot, or refers to a manifest that was moved/relinked after createAcpxPackageJsonResolver computed canonicalRoot.
Common situations: Global/pnpm-style symlinked node_modules where package dirs are symlinked into a virtual store outside the provider root; a stale or hand-built provider root where the issuer manifest is a relative path resolved wrongly; passing a workspace package.json from outside the ACPX provider installation as the issuer.
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
- Trusted viewer must not use symlinks
- ACPX provider package ${packageName} resolves outside the se
- ACPX ${agent} runtime executable must be a real regular file
- Access denied
- Registered base project workspace Paperclip config at ${conf
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/a9f72a4f09d61c25.
Report an issue: GitHub.