paperclipai/paperclip · error · ToolGatewayHttpError

action_issue_closed

action_issue_closed

Error message

The issue for this tool action is closed; the approval has expired

What it means

Post-claim recheck in approved-action execution: the issue tied to the invocation is done or cancelled (or missing), so the claimed approval is expired and marked as such. This closes the race where a claim committed just before terminal-issue expiry revocation, ensuring governed side effects never run for closed issues.

Solutions

  1. The issue was closed, expiring the approval. Reopen/use another issue and request a new approval.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/tool-gateway.ts:4137 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/a55b50e59067d86f. Report an issue: GitHub.

Appendix: source

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

        and(
          eq(issues.id, invocation.issueId!),
          eq(issues.companyId, invocation.companyId),
        ),
      )
      .limit(1);
    if (issue && issue.status !== "done" && issue.status !== "cancelled") {
      return { projectId: issue.projectId };
    }
    const expiredAt = new Date();
    await db
      .update(toolActionRequests)
      .set({ status: "expired", resolvedAt: expiredAt, updatedAt: expiredAt })
      .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),

View on GitHub (pinned to 3f1d897a7c)