paperclipai/paperclip · error · ToolGatewayHttpError
organization_authorization_required
organization_authorization_required
Error message
Organization authorization is required
What it means
This ToolGatewayHttpError (HTTP 409) is thrown by the tool gateway's grant resolution when a connection's credential policy requires an organization-level grant, but no active default organization grant (kind='organization', isDefault=true, status='active') exists in connection_grants for that connection. The gateway refuses to proceed because there is no consent boundary authorizing the shared credential. It is a setup/completeness problem, not a runtime failure.
Solutions
- Re-authorize the connection at the organization level (complete the connection OAuth/install flow so an active default organization grant is created in connection_grants).
- Inspect connection_grants for the connectionId: SELECT * FROM connection_grants WHERE connection_id = ... AND kind = 'organization'; confirm is_default=true and status='active', and re-activate or recreate the grant if it was revoked.
- If the connection should be per-user instead, change the connection's credentialPolicy so grant resolution looks for a user grant rather than an organization grant.
- Verify the connectionId in the failing tool call matches the connection the organization actually authorized (mis-scoped connection lookups surface as a missing grant).
Example fix
// before: grant row exists but inactive
UPDATE connection_grants SET status = 'active' WHERE connection_id = $1 AND kind = 'organization';
// after (preferred): re-run the connection authorization flow so the app inserts
// { kind: 'organization', isDefault: true, status: 'active' } itself
await connectionService.authorizeForOrganization(connectionId, actorUserId); Defensive patterns
Strategy: try-catch
Validate before calling
const [orgGrant] = await db.select().from(connectionGrants).where(and(eq(connectionGrants.connectionId, connectionId), eq(connectionGrants.kind, 'organization'), eq(connectionGrants.isDefault, true), eq(connectionGrants.status, 'active'))).limit(1);
if (!orgGrant) throw new Error(`Connection ${connectionId} has no active organization grant; authorize it first.`); Type guard
function hasActiveOrgGrant(g: ConnectionGrant | undefined): g is ConnectionGrant {
return !!g && g.kind === "organization" && g.isDefault === true && g.status === "active";
} Try / catch
try {
await callGovernedTool(session, connectionId, toolName, args);
} catch (e) {
if (e instanceof ToolGatewayHttpError && e.code === "organization_authorization_required") {
return { status: "needs_authorization", connectionId: e.details.connectionId };
}
throw e;
} Prevention
- After creating any organization-scoped connection, assert in tests that a default active organization grant row exists before enabling tool calls.
- Monitor for revoked/deactivated organization grants on connections that still have active sessions.
- Prefer the app's authorize flow over manual inserts so grant kind/isDefault/status invariants hold.
- Surface connection health/authorization state in the UI so agents are only pointed at fully authorized connections.
When it happens
Trigger: Calling a governed MCP tool through the tool gateway for a connection whose credential policy is 'organization' while the company has never completed (or has deactivated/removed) the default organization grant for that connection: e.g. the owner started OAuth connect but never finalized the org-wide authorization, or the grant row's status was flipped from 'active' to 'revoked'/'inactive'.
Common situations: An admin shared a connection at the organization level but the grant creation transaction never ran; a teammate removed or disabled the org grant while agents were still using the connection; a database restore/seeding dropped connection_grants rows so the connection exists but its grant does not.
Related errors
- grant_audience_denied
- mcp_transport_unsupported
- ambiguous_personal_grant
- Cloud control assertion stack does not match this instance
- github_identity_unavailable
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/dd767cc6af6b9711.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:4423
.limit(1);
return grant;
};
const findOrganizationGrant = async () => {
const [grant] = await db
.select()
.from(connectionGrants)
.where(
and(
eq(connectionGrants.companyId, connection.companyId),
eq(connectionGrants.connectionId, connection.id),
eq(connectionGrants.kind, "organization"),
eq(connectionGrants.isDefault, true),
eq(connectionGrants.status, "active"),
),
)
.limit(1);
if (!grant) {
throw new ToolGatewayHttpError(
409,
"Organization authorization is required",
"organization_authorization_required",
{
connectionId: connection.id,
},
);
}
const members = await db
.select({ subjectId: connectionGrantMembers.subjectId })
.from(connectionGrantMembers)
.where(
and(
eq(connectionGrantMembers.companyId, connection.companyId),
eq(connectionGrantMembers.grantId, grant.id),
eq(connectionGrantMembers.subjectType, "user"),
),
);View on GitHub (pinned to 3f1d897a7c)