paperclipai/paperclip · error · Error
ACPX provider credential fence is invalid
Error message
ACPX provider credential fence is invalid
What it means
Before spawning a guarded (credential-fenced) ACPX provider child process, the VerifiedAcpxProviderLifetime argument is validated. The throw fires when the lifetime lease passed as the third argument to spawn() is malformed: credentialFenceFds must be an array of exactly two distinct, non-negative safe integers, and activateCredentialFenceOwner must be a callable. The library throws this to fail fast rather than spawn a child with an unusable credential fence.
Source
Thrown at packages/paperclip-runner/src/drivers/acpx/installation-integrity.ts:1350
const providerRuntimeExecutableCount =
providerRuntimeExecutable === null ? 0 : 1;
const providerGuardianFd =
DEPENDENCY_ANCESTOR_FD_START +
dependencyAncestors.length +
providerRuntimeExecutableCount;
const providerOwnershipFd = providerGuardianFd + 1;
const providerExitFd = providerOwnershipFd + 1;
if (
guarded &&
(!Array.isArray(lifetime.credentialFenceFds) ||
lifetime.credentialFenceFds.length !== 2 ||
lifetime.credentialFenceFds.some(
(fd) => !Number.isSafeInteger(fd) || fd < 0,
) ||
lifetime.credentialFenceFds[0] === lifetime.credentialFenceFds[1] ||
typeof lifetime.activateCredentialFenceOwner !== "function")
) {
throw new Error("ACPX provider credential fence is invalid");
}
const runtimeTargetFd = guarded
? providerExitFd + 3
: DEPENDENCY_ANCESTOR_FD_START +
dependencyAncestors.length +
providerRuntimeExecutableCount;
const runtimeHandoff =
verifiedRuntimeExecutableHandoff(runtimeTargetFd);
const environment = sanitizedNodeEnvironment(options.env);
delete environment[ACPX_PRIVATE_SNAPSHOT_ENV];
if (privateSnapshot) environment[ACPX_PRIVATE_SNAPSHOT_ENV] = JSON.stringify(privateSnapshot.handoff);
if (runtimeHandoff.environmentValue === undefined) {
delete environment[VERIFIED_RUNTIME_EXECUTABLE_ENV];
} else {
environment[VERIFIED_RUNTIME_EXECUTABLE_ENV] =
runtimeHandoff.environmentValue;
}
if (View on GitHub (pinned to 01ad858492)
Solutions
- Obtain the lifetime from the library's own credential-fence creation path instead of constructing it manually.
- Validate lifetime.credentialFenceFds: length 2, both Number.isSafeInteger and >= 0, and fds differ.
- Ensure activateCredentialFenceOwner is passed as an actual function reference, not JSON-serialized or copied across a process boundary.
- If the fence fds were closed/released, create a fresh fence rather than reusing the old lifetime.
Example fix
// before
await provider.spawn(args, {}, { credentialFenceFds: [12, 12], activateCredentialFenceOwner: undefined });
// after
const lifetime = createVerifiedAcpxProviderLifetime(); // library-provided
await provider.spawn(args, {}, lifetime); Defensive patterns
Strategy: validation
Validate before calling
function isValidLifetime(lt) {
return !!lt && Array.isArray(lt.credentialFenceFds) && lt.credentialFenceFds.length === 2 &&
lt.credentialFenceFds.every((fd) => Number.isSafeInteger(fd) && fd >= 0) &&
lt.credentialFenceFds[0] !== lt.credentialFenceFds[1] &&
typeof lt.activateCredentialFenceOwner === "function";
}
if (!isValidLifetime(lifetime)) throw new TypeError("lifetime must come from the credential fence factory"); Type guard
const isValidLifetime = (lt): lt is VerifiedAcpxProviderLifetime => Array.isArray(lt?.credentialFenceFds) && lt.credentialFenceFds.length === 2 && lt.credentialFenceFds.every((fd) => Number.isSafeInteger(fd) && fd >= 0) && lt.credentialFenceFds[0] !== lt.credentialFenceFds[1] && typeof lt?.activateCredentialFenceOwner === "function";
Prevention
- Always get lifetimes from the library's fence factory, never hand-built or JSON-serialized
- Never pass a lifetime across process/worker boundaries (functions do not survive)
- Create a fresh fence after closing a previous one instead of reusing fds
When it happens
Trigger: Calling verifiedAcpxProvider.spawn(args, options, lifetime) where lifetime.credentialFenceFds is not an array, has length != 2, contains a non-safe-integer or negative fd, has both fds equal, or lifetime.activateCredentialFenceOwner is not a function.
Common situations: Hand-constructing a VerifiedAcpxProviderLifetime object instead of receiving it from the library's lease/fence factory; reusing a fence whose fds were already closed and reset to -1; passing a stub lifetime in tests; destructuring/serializing the lifetime (e.g. across a worker boundary) which turns the function into undefined.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ACPX provider runtime executable lease is invalid
- ACPX provider package ancestry is invalid
- The setup-token login session could not start.
- ACPX provider dependency ancestry is invalid
- ACPX provider runtime executable count is invalid
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/ca4dad36b8083fc3.
Report an issue: GitHub.