paperclipai/paperclip · error · Error
ACPX provider lifetime fence candidates are invalid
Error message
ACPX provider lifetime fence candidates are invalid
What it means
validateFenceCandidates requires the provider lifetime fence candidates to be exactly an array of 3 distinct safe integers in the ephemeral/dynamic port range 49152–65535. These ports are used to fence provider lifetime across session recovery. Anything else (wrong length, duplicates, out-of-range, non-integer) is rejected with this error so recovery cannot proceed against invalid fencing data.
Source
Thrown at packages/paperclip-runner/src/drivers/acpx/recovery-identity.ts:277
!isPermissionMode(expected.permissionMode)
) {
throw new Error("Expected ACPX permission mode is invalid");
}
validateFenceCandidates(expected.providerLifetimeFenceCandidates);
}
function validateFenceCandidates(
value: unknown,
): asserts value is readonly [number, number, number] {
if (
!Array.isArray(value) ||
value.length !== 3 ||
value.some(
(port) => !Number.isSafeInteger(port) || port < 49_152 || port > 65_535,
) ||
new Set(value).size !== 3
) {
throw new Error("ACPX provider lifetime fence candidates are invalid");
}
}
function sameFenceCandidates(
left: readonly [number, number, number],
right: readonly [number, number, number],
): boolean {
return left.every((port, index) => port === right[index]);
}
async function resolveWorkspace(value: string): Promise<string> {
if (!value.trim()) throw new Error("ACPX working directory is required");
const workspacePath = await realpath(value);
const metadata = await stat(workspacePath);
if (!metadata.isDirectory() || workspacePath === dirname(workspacePath)) {
throw new Error("ACPX working directory must be a non-root directory");
}
return workspacePath;View on GitHub (pinned to 01ad858492)
Solutions
- Regenerate fence candidates so they are 3 distinct safe integers within 49152–65535 (the OS ephemeral range).
- Discard the corrupt persisted record and start a new session so the library can regenerate valid candidates.
- Fix fixtures/tests to build candidates with the library's own generator rather than hardcoding.
- If you persist records through your own pipeline, validate the 3-distinct-ephemeral-ports invariant before writing.
Example fix
// before const candidates = [8080, 8080]; // reserved ports and duplicates // after const candidates = [49152 + 100, 49152 + 200, 49152 + 300]; // distinct, in 49152-65535
Defensive patterns
Strategy: validation
Validate before calling
const valid = (c: unknown): c is [number, number, number] => Array.isArray(c) && c.length === 3 && c.every((p) => Number.isSafeInteger(p) && p >= 49152 && p <= 65535) && new Set(c).size === 3;
Try / catch
try {
const record = parsePersistedRecord(raw);
} catch (e) {
if (e.message === "ACPX provider lifetime fence candidates are invalid") {
return startFreshSession(); // regenerate valid candidates
}
throw e;
} Prevention
- Generate fence candidates with the library's own generator, not hardcoded ports.
- Only use distinct ports from the 49152–65535 ephemeral range.
- Validate record JSON invariants before persisting through custom pipelines.
When it happens
Trigger: Parsing a persisted identity record (via validatedRecord) or validating an expected identity (via validateExpected) whose providerLifetimeFenceCandidates is not an array of exactly 3 distinct integers in [49152, 65535] — e.g. undefined, empty array, port 80, or repeated ports.
Common situations: Hand-crafted test fixtures with placeholder ports; records truncated by a bad serializer; code generating fence candidates from a reserved port range; JSON round-trips that lost array elements or produced floats.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- persisted Codex ACPX session identity is inconsistent
- ACPX identity permission mode is invalid
- ACPX sidecar runtime context must be pre-materialized
- providerLifetimeFenceCandidates must be three distinct priva
- persisted Codex ACPX resultless recovery requires a complete
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/28b7c762b5faadf9.
Report an issue: GitHub.