paperclipai/paperclip · error · ToolGatewayHttpError

formal_approval_required

formal_approval_required

Error message

Tool action request requires formal board approval before execution

What it means

Governance guard during approval resolution: the action request references a formal approvals row that is missing or not in approved status. The 409 formal_approval_required blocks execution until the board formally approves the linked approval record, since this action was configured to require formal approval.

Solutions

  1. This action requires formal board approval; route it through the board approval flow instead of executing directly.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/tool-gateway.ts:5282 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/38336dae0cec2619. Report an issue: GitHub.

Appendix: source

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

        throw new ToolGatewayHttpError(
          409,
          "Tool action request is no longer approvable; refresh the review queue",
          "action_request_invalidated",
        );
      }
      if (actionRequest.approvalId) {
        const [formalApproval] = await db
          .select({ status: approvals.status })
          .from(approvals)
          .where(
            and(
              eq(approvals.id, actionRequest.approvalId),
              eq(approvals.companyId, input.companyId),
            ),
          )
          .limit(1);
        if (!formalApproval || formalApproval.status !== "approved") {
          throw new ToolGatewayHttpError(
            409,
            "Tool action request requires formal board approval before execution",
            "formal_approval_required",
            { approvalId: actionRequest.approvalId },
          );
        }
      }
      if (actionRequest.status === "approved") {
        await reflectToolActionInteractionLifecycle({
          actionRequestId: actionRequest.id,
          status: "approved",
        });
        if (
          !isTestOriginInvocation(invocation) &&
          signedPayload.executionOnApprove === true
        ) {
          try {
            await executeApprovedAgentInvocation({ actionRequest, invocation });

View on GitHub (pinned to 3f1d897a7c)