{"record":{"id":"1205f079c9e5815e","repo":"paperclipai/paperclip","slug":"acpx-identity-permission-mode-is-invalid","errorCode":null,"errorMessage":"ACPX identity permission mode is invalid","messagePattern":"ACPX identity permission mode is invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/acpx/recovery-identity.ts","lineNumber":233,"sourceCode":"  if (value.schema !== ACPX_IDENTITY_RECORD_SCHEMA) {\n    throw new Error(\"Unsupported ACPX identity record schema\");\n  }\n  for (const field of [\n    \"normalizedSessionId\",\n    \"acpxRecordId\",\n    \"backendSessionId\",\n    \"agentSessionId\",\n    \"requestedModel\",\n    \"effectiveModel\",\n  ] as const) {\n    validateIdentity(value[field], field);\n  }\n  for (const field of [\"profileDigest\", \"workspaceDigest\"] as const) {\n    if (!isDigest(value[field]))\n      throw new Error(`ACPX identity ${field} is invalid`);\n  }\n  if (!isPermissionMode(value.permissionMode)) {\n    throw new Error(\"ACPX identity permission mode is invalid\");\n  }\n  validateFenceCandidates(value.providerLifetimeFenceCandidates);\n  return value as unknown as AcpxIdentityRecord;\n}\n\nfunction validateExpected(expected: AcpxExpectedSessionIdentity): void {\n  if (expected.kind !== \"acpx\") throw new Error(\"Expected ACPX identity kind\");\n  for (const value of [\n    expected.normalizedSessionId,\n    expected.acpxRecordId,\n    expected.backendSessionId,\n    expected.agentSessionId,\n    expected.requestedModel,\n    expected.effectiveModel,\n  ]) {\n    validateIdentity(value, \"expected ACPX\");\n  }\n  if (","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/acpx/recovery-identity.ts#L215-L251","documentation":"validatedRecord re-validates every field of a persisted ACPX identity record parsed from disk. When the permissionMode field is not one of the known permission modes (per isPermissionMode), the record is considered corrupt or foreign and this error is thrown. This happens before any recovery logic runs, so a tampered or version-skewed record never reaches session handling.","triggerScenarios":"Loading a persisted AcpxIdentityRecord whose permissionMode field is missing, null, an unknown string, or a mode introduced by a different/newer version of the library — via parsePersistedRecord() during session recovery.","commonSituations":"Manual editing or partial truncation of the runtime record file; a newer runner version writing modes an older parser does not know; a corrupted disk state or hand-rolled record in tests.","solutions":["Discard the stale runtime directory/record and start a new session — the record cannot be trusted.","Align runner versions: recover the session with the same library version that wrote it.","Verify the record file's permissionMode value against the library's accepted permission modes before manual editing.","If you must keep the session, re-create the identity record programmatically via createAcpxIdentityRecord with a valid permissionMode."],"exampleFix":"// before\nconst record = { permissionMode: \"yolo\" }; // not a known mode\n// after\nconst record = { permissionMode: \"default\" }; // value accepted by isPermissionMode","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const KNOWN_MODES = new Set([\"default\", \"acceptEdits\", \"bypassAll\"]);\nconst isValidRecord = (v: unknown): v is AcpxIdentityRecord =>\n  typeof v === \"object\" && v !== null && \"permissionMode\" in v &&\n  KNOWN_MODES.has((v as { permissionMode: string }).permissionMode);","tryCatchPattern":"try {\n  const record = parsePersistedRecord(raw);\n} catch (e) {\n  if (e.message === \"ACPX identity permission mode is invalid\") {\n    discardRuntimeDirectory(sessionId); // corrupt/foreign record\n    return startFreshSession();\n  }\n  throw e;\n}","preventionTips":["Never hand-edit persisted identity records.","Recover sessions with the same library version that wrote them.","Delete runtime directories from failed migrations rather than patching their records."],"tags":["validation","persistence","enum","acpx"],"backgroundTag":"invalid-enum-value","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"}