{"record":{"id":"b88ddfadfe005e57","repo":"paperclipai/paperclip","slug":"identity-context-unavailable","errorCode":"identity_context_unavailable","errorMessage":"Approved action identity is unavailable","messagePattern":"Approved action identity is unavailable","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":409,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":7571,"sourceCode":"\n  async function restoreApprovedActionIdentity(\n    session: ToolGatewaySession,\n    identityContextId: string | undefined,\n  ) {\n    if (!identityContextId) return;\n    const [origin] = await db\n      .select()\n      .from(runIdentityContexts)\n      .where(\n        and(\n          eq(runIdentityContexts.id, identityContextId),\n          eq(runIdentityContexts.companyId, session.companyId),\n          eq(runIdentityContexts.runId, session.runId!),\n          eq(runIdentityContexts.status, \"accepted\"),\n        ),\n      );\n    if (!origin)\n      throw new ToolGatewayHttpError(\n        409,\n        \"Approved action identity is unavailable\",\n        \"identity_context_unavailable\",\n      );\n    session.identityContextId = origin.id;\n    session.responsibleUserId =\n      origin.cause === \"company_default\" ? null : origin.responsibleUserId;\n  }\n\n  async function executeApprovedAgentInvocation(input: {\n    actionRequest: typeof toolActionRequests.$inferSelect;\n    invocation: typeof toolInvocations.$inferSelect;\n  }) {\n    const { actionRequest, invocation } = input;\n    if (\n      !invocation.agentId ||\n      !invocation.issueId ||\n      isTestOriginInvocation(invocation)","sourceCodeStart":7553,"sourceCodeEnd":7589,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/tool-gateway.ts#L7553-L7589","documentation":"Before executing an approved action, the gateway restores the identity context that was accepted at approval time. It looks up run_identity_contexts by id, company, run, and status 'accepted'; if no such accepted row exists, the approved identity cannot be re-established and execution is refused with a 409.","triggerScenarios":"executeApprovedAgentInvocation path calls restoreApprovedActionIdentity with an identityContextId that is missing, belongs to another company/run, or whose status is not 'accepted' (pending, rejected, or reset).","commonSituations":"Identity context was reset/re-requested after approval (status changed), run was restarted with new identity contexts, stale signed payload replayed after company data moved, or the row was deleted by cleanup.","solutions":["Re-run the approval flow so a fresh accepted run_identity_contexts row is created, then approve again","Verify the identityContextId in the signed payload matches the current run (not an old run's context)","Check run_identity_contexts status: re-accept the pending identity context before approving"],"exampleFix":"// before: stale context id\nawait restoreApprovedActionIdentity(session, staleIdentityContextId);\n// after: re-request approval with current accepted context\nconst [origin] = await db.select().from(runIdentityContexts).where(eq(runIdentityContexts.runId, session.runId));\nif (origin?.status !== 'accepted') throw new Error('Re-approve: identity context not accepted');","handlingStrategy":"validation","validationCode":"const [ctx] = await db.select().from(runIdentityContexts).where(and(eq(runIdentityContexts.id, identityContextId), eq(runIdentityContexts.status, 'accepted')));\nif (!ctx) throw new Error('Identity context not accepted; re-run approval');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never reuse signed payloads across runs or identity resets","Re-request approval whenever the identity context changes status","Avoid deleting run_identity_contexts rows while actions are pending"],"tags":["identity","approval","state"],"backgroundTag":"record-not-found","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}