paperclipai/paperclip · error · ToolGatewayHttpError

identity_context_unavailable

identity_context_unavailable

Error message

Approved action identity is unavailable

What it means

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.

Source

Thrown at server/src/services/tool-gateway.ts:5578

      .where(eq(toolActionRequests.id, claimed.id));
    await reflectToolActionInteractionLifecycle({ actionRequestId: claimed.id, status: "expired" });
    throw new ToolGatewayHttpError(
      409,
      "The issue for this tool action is closed; the approval has expired",
      "action_issue_closed",
      { actionRequestId: claimed.id, invocationId: invocation.id },
    );
  }

  async function restoreApprovedActionIdentity(session: ToolGatewaySession, identityContextId: string | undefined) {
    if (!identityContextId) return;
    const [origin] = await db.select().from(runIdentityContexts).where(and(
      eq(runIdentityContexts.id, identityContextId),
      eq(runIdentityContexts.companyId, session.companyId),
      eq(runIdentityContexts.runId, session.runId!),
      eq(runIdentityContexts.status, "accepted"),
    ));
    if (!origin) throw new ToolGatewayHttpError(409, "Approved action identity is unavailable", "identity_context_unavailable");
    session.identityContextId = origin.id;
    session.responsibleUserId = origin.cause === "company_default" ? null : origin.responsibleUserId;
  }

  async function executeApprovedAgentInvocation(input: {
    actionRequest: typeof toolActionRequests.$inferSelect;
    invocation: typeof toolInvocations.$inferSelect;
  }) {
    const { actionRequest, invocation } = input;
    if (!invocation.agentId || !invocation.issueId || isTestOriginInvocation(invocation)) {
      throw new ToolGatewayHttpError(409, "Tool action request is not an agent-origin action", "action_origin_invalid");
    }

    const [claimed] = await db
      .update(toolActionRequests)
      .set({ status: "executing", updatedAt: new Date() })
      .where(and(eq(toolActionRequests.id, actionRequest.id), eq(toolActionRequests.status, "approved")))
      .returning();

View on GitHub (pinned to 01ad858492)

Solutions

  1. Re-run the approval flow so a fresh accepted run_identity_contexts row is created, then approve again
  2. Verify the identityContextId in the signed payload matches the current run (not an old run's context)
  3. Check run_identity_contexts status: re-accept the pending identity context before approving

Example fix

// before: stale context id
await restoreApprovedActionIdentity(session, staleIdentityContextId);
// after: re-request approval with current accepted context
const [origin] = await db.select().from(runIdentityContexts).where(eq(runIdentityContexts.runId, session.runId));
if (origin?.status !== 'accepted') throw new Error('Re-approve: identity context not accepted');
Defensive patterns

Strategy: validation

Validate before calling

const [ctx] = await db.select().from(runIdentityContexts).where(and(eq(runIdentityContexts.id, identityContextId), eq(runIdentityContexts.status, 'accepted')));
if (!ctx) throw new Error('Identity context not accepted; re-run approval');

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/b88ddfadfe005e57. Report an issue: GitHub.