{"record":{"id":"bc4bae284f063ef5","repo":"paperclipai/paperclip","slug":"agent-authorization-required","errorCode":"agent_authorization_required","errorMessage":"A dedicated agent authorization is required","messagePattern":"A dedicated agent authorization is required","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":409,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":3339,"sourceCode":"        eq(companyMemberships.status, \"active\"),\n      )).limit(1).then((rows) => rows[0] ?? null) : null;\n      if (!isConnectionGrantAudienceAllowed(\n        members.map((member) => member.subjectId),\n        actingUserId,\n        Boolean(activeAudienceMember),\n      )) {\n        throw new ToolGatewayHttpError(403, \"The acting user is not in this grant's audience\", \"grant_audience_denied\", {\n          connectionId: connection.id,\n          grantId: grant.id,\n          actingUserId,\n        });\n      }\n      return grant;\n    };\n\n    if (connection.credentialPolicy === \"per_agent\") {\n      if (!session.agentId) {\n        throw new ToolGatewayHttpError(409, \"A dedicated agent authorization is required\", \"agent_authorization_required\", {\n          connectionId: connection.id,\n        });\n      }\n      const [agentGrant] = await db.select().from(connectionGrants).where(and(\n        eq(connectionGrants.companyId, connection.companyId),\n        eq(connectionGrants.connectionId, connection.id),\n        eq(connectionGrants.kind, \"agent\"),\n        eq(connectionGrants.subjectAgentId, session.agentId),\n        eq(connectionGrants.status, \"active\"),\n      )).limit(1);\n      if (!agentGrant) {\n        throw new ToolGatewayHttpError(409, \"This agent's dedicated authorization is not connected\", \"agent_authorization_required\", {\n          connectionId: connection.id,\n          agentId: session.agentId,\n        });\n      }\n      return agentGrant;\n    }","sourceCodeStart":3321,"sourceCodeEnd":3357,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-gateway.ts#L3321-L3357","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Invoke the connection from an agent session that has an agentId","Change the connection's credentialPolicy to a shared policy if agent-dedicated grants are not needed","Authorize an agent grant for the calling agent if policy is correct but the session is right","Check which session type is being used — board operator sessions cannot use per-agent connections"],"exampleFix":"// before\nconst session = await createBoardSession(companyId); // no agentId\ncallTool(session, perAgentConnId, p); // 409\n// after\nconst session = await createAgentSession({ companyId, agentId });\ncallTool(session, perAgentConnId, p);","handlingStrategy":"validation","validationCode":"if (connection.credentialPolicy === \"per_agent\" && !session.agentId) {\n  throw new Error(\"per_agent connection requires an agent session\");\n}","typeGuard":"function isAgentSession(s: Session): s is Session & { agentId: string } {\n  return typeof (s as { agentId?: string }).agentId === \"string\";\n}","tryCatchPattern":"try { await gateway.callTool(session, connId, p); }\ncatch (e) {\n  if (e.code === \"agent_authorization_required\") await runAgentAuthorizationFlow(connId, session.agentId);\n  else throw e;\n}","preventionTips":["Check credentialPolicy before choosing the session type for a tool call","Use shared policy connections for board/operator ad-hoc testing","Document that per_agent connections are agent-only","Route board-initiated calls through a designated service agent"],"tags":["authorization","connector","agent","configuration"],"backgroundTag":"authentication-required","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}