{"record":{"id":"1ed6fce29444d339","repo":"paperclipai/paperclip","slug":"providerlifetimefencecandidates-must-be-three-dist","errorCode":null,"errorMessage":"providerLifetimeFenceCandidates must be three distinct private ports","messagePattern":"providerLifetimeFenceCandidates must be three distinct private ports","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/cli/acpx-runtime-sidecar.ts","lineNumber":1111,"sourceCode":"      : { permissionMode: requiredPermissionMode(input.permissionMode) }),\n    providerLifetimeFenceCandidates: requiredFenceCandidates(\n      input.providerLifetimeFenceCandidates,\n    ),\n  };\n}\n\nfunction requiredFenceCandidates(\n  value: unknown,\n): readonly [number, number, number] {\n  if (\n    !Array.isArray(value) ||\n    value.length !== 3 ||\n    value.some(\n      (port) => !Number.isSafeInteger(port) || port < 49_152 || port > 65_535,\n    ) ||\n    new Set(value).size !== 3\n  ) {\n    throw new Error(\n      \"providerLifetimeFenceCandidates must be three distinct private ports\",\n    );\n  }\n  return Object.freeze([...value]) as readonly [number, number, number];\n}\n\nfunction requiredPermissionMode(\n  value: unknown,\n): AcpxSidecarOpenParams[\"permissionMode\"] {\n  if (\n    value === \"approve-all\" ||\n    value === \"approve-reads\" ||\n    value === \"deny-all\"\n  ) {\n    return value;\n  }\n  throw new Error(\n    \"permissionMode must be approve-all, approve-reads, or deny-all\",","sourceCodeStart":1093,"sourceCodeEnd":1129,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/cli/acpx-runtime-sidecar.ts#L1093-L1129","documentation":"providerLifetimeFenceCandidates must be exactly three distinct TCP ports in the private/dynamic range (49152-65535); the validator freezes the tuple only when the shape, range, and uniqueness checks all pass. This prevents fence ports from colliding or overlapping with privileged ranges.","triggerScenarios":"Passing an array whose length is not 3, containing non-integer or out-of-range ports (<49152 or >65535), or containing duplicate port values.","commonSituations":"Config with two or three identical ports from copy-paste; ports picked from the well-known/registered range; a config loader returning a 2-element list after dropping a duplicate.","solutions":["Provide exactly three different ports, each between 49152 and 65535","Fix the config source so duplicates are resolved before validation","Generate three distinct ephemeral ports programmatically"],"exampleFix":"// before\nnormalizeFenceCandidates([49200, 49200, 49300]);\n// after\nnormalizeFenceCandidates([49200, 49201, 49300]);","handlingStrategy":"validation","validationCode":"function validFencePorts(ports) { return Array.isArray(ports) && ports.length === 3 && ports.every(p => Number.isSafeInteger(p) && p >= 49152 && p <= 65535) && new Set(ports).size === 3; }\nif (!validFencePorts(config.providerLifetimeFenceCandidates)) throw new Error('need three distinct ports in 49152-65535');","typeGuard":"function isFenceCandidateTuple(v: unknown): v is readonly [number, number, number] {\n  return Array.isArray(v) && v.length === 3 && v.every((p): p is number => Number.isSafeInteger(p) && p >= 49152 && p <= 65535) && new Set(v).size === 3;\n}","tryCatchPattern":"try { configureFences(cfg.providerLifetimeFenceCandidates); }\ncatch (e) { if (String(e.message).includes('three distinct private ports')) { cfg.providerLifetimeFenceCandidates = pickDistinctEphemeralPorts(3); configureFences(cfg.providerLifetimeFenceCandidates); } else throw e; }","preventionTips":["Validate port config at load time, before the sidecar starts","Use a config schema with min/max/uniqueness constraints for port arrays","Generate ephemeral ports programmatically instead of hardcoding"],"tags":["validation","ports","config"],"backgroundTag":"value-out-of-range","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}