{"record":{"id":"ddda183a7a6ab71a","repo":"paperclipai/paperclip","slug":"acpx-provider-identity-contains-invalid-lifetime-f","errorCode":null,"errorMessage":"ACPX provider identity contains invalid lifetime fences","messagePattern":"ACPX provider identity contains invalid lifetime fences","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts","lineNumber":88,"sourceCode":"    permissionMode !== \"deny-all\"\n  ) {\n    throw new Error(\n      \"ACPX provider identity contains an invalid permission mode\",\n    );\n  }\n  const fenceCandidates = identity.providerLifetimeFenceCandidates;\n  if (\n    !Array.isArray(fenceCandidates) ||\n    fenceCandidates.length !== 3 ||\n    fenceCandidates.some(\n      (candidate) =>\n        !Number.isInteger(candidate) ||\n        candidate < 49_152 ||\n        candidate > 65_535,\n    ) ||\n    new Set(fenceCandidates).size !== 3\n  ) {\n    throw new Error(\"ACPX provider identity contains invalid lifetime fences\");\n  }\n  return {\n    kind: \"acpx\",\n    normalizedSessionId: identity.normalizedSessionId as string,\n    acpxRecordId: identity.acpxRecordId as string,\n    backendSessionId: identity.backendSessionId as string,\n    agentSessionId: identity.agentSessionId as string,\n    profileDigest: identity.profileDigest as string,\n    workspaceDigest: identity.workspaceDigest as string,\n    requestedModel: identity.requestedModel as string,\n    effectiveModel: identity.effectiveModel as string,\n    ...(permissionMode === undefined ? {} : { permissionMode }),\n    providerLifetimeFenceCandidates: fenceCandidates as [\n      number,\n      number,\n      number,\n    ],\n  };","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts#L70-L106","documentation":"parseProviderIdentity requires providerLifetimeFenceCandidates to be an array of exactly 3 distinct integers, each within the inclusive range 49152–65535 (the dynamic/ephemeral port range). These fences are unique lifetime markers for the ACPX provider identity. If the field is missing, not an array, has the wrong length, contains non-integers or out-of-range values, or contains duplicates, the parser throws this error instead of returning an identity.","triggerScenarios":"Calling parseProviderIdentity with an ACPX-kind identity whose providerLifetimeFenceCandidates is absent, has fewer/more than 3 entries, contains values below 49152 or above 65535, contains non-integer values (floats, strings, null), or repeats a value so the Set size is not 3.","commonSituations":"Corrupted or truncated persistence files; older driver versions that stored a different fence format; manual edits that introduced duplicate or out-of-range fence values; JSON round-trips that coerced integers to strings or floats.","solutions":["Check the persisted identity's providerLifetimeFenceCandidates and make it an array of exactly 3 distinct integers in [49152, 65535], e.g. [49152, 57344, 65535].","Confirm the file was written by a compatible paperclip-runner version; if a format change occurred, migrate the stored record or re-create the session.","If the record is unreadable, abandon the persisted session and open a new Codex session so fresh fences are generated."],"exampleFix":"// before\n{ \"providerLifetimeFenceCandidates\": [49152, 49152, 70000] }\n// after\n{ \"providerLifetimeFenceCandidates\": [49152, 57344, 65535] }","handlingStrategy":"validation","validationCode":"function hasValidFences(identity) {\n  const f = identity?.providerLifetimeFenceCandidates;\n  return Array.isArray(f) && f.length === 3 &&\n    f.every((n) => Number.isInteger(n) && n >= 49152 && n <= 65535) &&\n    new Set(f).size === 3;\n}\nif (!hasValidFences(storedIdentity)) {\n  throw new Error(\"stored identity has invalid lifetime fences\");\n}","typeGuard":"function isValidFenceArray(v: unknown): v is [number, number, number] {\n  return Array.isArray(v) && v.length === 3 &&\n    v.every((n) => Number.isInteger(n) && n >= 49_152 && n <= 65_535) &&\n    new Set(v).size === 3;\n}","tryCatchPattern":null,"preventionTips":["Validate the identity record with a schema (zod/JSON Schema) before persisting it, not only when reading it back.","Avoid manual edits or lossy JSON transforms (string coercion) of persistence files.","Keep writer and reader driver versions in sync so the fence format cannot drift."],"tags":["validation","config","codex","session-recovery"],"backgroundTag":"schema-validation-failed","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"}