paperclipai/paperclip · error · ToolGatewayHttpError

agent_authorization_required

agent_authorization_required

Error message

A dedicated agent authorization is required

What it means

Thrown when a connection uses the per_agent credential policy but the calling session has no agentId. Per-agent connections require each agent to use its own dedicated grant; a session without an agent identity cannot select any grant, so a 409 is raised.

Source

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

        eq(companyMemberships.status, "active"),
      )).limit(1).then((rows) => rows[0] ?? null) : null;
      if (!isConnectionGrantAudienceAllowed(
        members.map((member) => member.subjectId),
        actingUserId,
        Boolean(activeAudienceMember),
      )) {
        throw new ToolGatewayHttpError(403, "The acting user is not in this grant's audience", "grant_audience_denied", {
          connectionId: connection.id,
          grantId: grant.id,
          actingUserId,
        });
      }
      return grant;
    };

    if (connection.credentialPolicy === "per_agent") {
      if (!session.agentId) {
        throw new ToolGatewayHttpError(409, "A dedicated agent authorization is required", "agent_authorization_required", {
          connectionId: connection.id,
        });
      }
      const [agentGrant] = await db.select().from(connectionGrants).where(and(
        eq(connectionGrants.companyId, connection.companyId),
        eq(connectionGrants.connectionId, connection.id),
        eq(connectionGrants.kind, "agent"),
        eq(connectionGrants.subjectAgentId, session.agentId),
        eq(connectionGrants.status, "active"),
      )).limit(1);
      if (!agentGrant) {
        throw new ToolGatewayHttpError(409, "This agent's dedicated authorization is not connected", "agent_authorization_required", {
          connectionId: connection.id,
          agentId: session.agentId,
        });
      }
      return agentGrant;
    }

View on GitHub (pinned to 01ad858492)

Solutions

  1. Invoke the connection from an agent session that has an agentId
  2. Change the connection's credentialPolicy to a shared policy if agent-dedicated grants are not needed
  3. Authorize an agent grant for the calling agent if policy is correct but the session is right
  4. Check which session type is being used — board operator sessions cannot use per-agent connections

Example fix

// before
const session = await createBoardSession(companyId); // no agentId
callTool(session, perAgentConnId, p); // 409
// after
const session = await createAgentSession({ companyId, agentId });
callTool(session, perAgentConnId, p);
Defensive patterns

Strategy: validation

Validate before calling

if (connection.credentialPolicy === "per_agent" && !session.agentId) {
  throw new Error("per_agent connection requires an agent session");
}

Type guard

function isAgentSession(s: Session): s is Session & { agentId: string } {
  return typeof (s as { agentId?: string }).agentId === "string";
}

Try / catch

try { await gateway.callTool(session, connId, p); }
catch (e) {
  if (e.code === "agent_authorization_required") await runAgentAuthorizationFlow(connId, session.agentId);
  else throw e;
}

Prevention

When it happens

Trigger: resolveConnectionGrant sees connection.credentialPolicy === 'per_agent' and session.agentId is undefined — e.g. a board/user-context session or a system job invoking an agent-only connection.

Common situations: Testing a per-agent connection from the board UI (no agent context); running the connection through a script/CLI without agent credentials; misconfiguring a shared connection as per_agent when it should be shared/company policy.

Related errors


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