paperclipai/paperclip · error · ToolGatewayHttpError
github_identity_unavailable
github_identity_unavailable
Error message
No GitHub identity connected
What it means
The Paperclip tool gateway resolves a managed GitHub identity for the session before dispatching a call through a connection whose source template is "github". If resolveManagedGitHubIdentitySelection finds no identity grant for the company/responsible user (and standing delegation is disallowed), the gateway aborts with HTTP 409 and code github_identity_unavailable. It means the agent session has no usable GitHub identity to act as.
Source
Thrown at server/src/services/tool-gateway.ts:2078
async function findToolForSession(session: ToolGatewaySession, toolName: string): Promise<ToolGatewayDescriptor> {
const connectedTools = await connectedMcpToolsForCompany(session.companyId);
const hasOnDemandTargets = connectedTools.some(isOnDemandRemoteTool);
const virtualTools = hasOnDemandTargets ? VIRTUAL_TOOLS : [];
const tool = [...allTools(), ...connectedTools, ...virtualTools]
.filter((candidate) => session.agentId || (candidate.providerType !== "paperclip_self" && candidate.providerType !== "paperclip_plugin"))
.find((candidate) => candidate.name === toolName);
if (!tool) {
throw new ToolGatewayHttpError(404, `Tool "${toolName}" not found`, "tool_not_found", { tool: toolName });
}
if (session.identityContextId && session.agentId && tool.connectionId) {
const [connection] = await db.select().from(toolConnections).where(and(
eq(toolConnections.id, tool.connectionId), eq(toolConnections.companyId, session.companyId),
));
if (connection?.config.sourceTemplateKey === "github" || connection?.transportConfig?.sourceTemplateKey === "github") {
let selected = await resolveManagedGitHubIdentitySelection(db, session.companyId, {
agentId: session.agentId, responsibleUserId: session.responsibleUserId, allowStandingDelegation: false,
});
if (!selected.grant) throw new ToolGatewayHttpError(409, selected.error ?? "No GitHub identity connected", "github_identity_unavailable");
const original = selected.grant;
// Acquire before policy evaluation or dispatch. An alternate connection
// gets its own catalog descriptor and policy checks; never replay a call.
for (let attempt = 0; attempt < 2; attempt += 1) {
const grant = selected.grant!;
const target = connectedTools.find((candidate) => candidate.connectionId === grant.connectionId
&& candidate.upstreamToolName === tool.upstreamToolName && candidate.providerType === tool.providerType);
if (!target) throw new ToolGatewayHttpError(404, "This GitHub tool is unavailable for the responsible person", "github_tool_unavailable");
const [selectedConnection] = await db.select().from(toolConnections).where(and(
eq(toolConnections.id, grant.connectionId), eq(toolConnections.companyId, session.companyId),
));
if (!selectedConnection) throw new ToolGatewayHttpError(409, "GitHub connection is unavailable", "github_identity_unavailable");
if (attempt === 0) await resolveConnectionGrant(session, selectedConnection);
try {
const headers = await resolveCredentialHeaders(session, selectedConnection, grant);
githubOperationCredentials.set(session, { grant, headers });
return target;
} catch (error) {View on GitHub (pinned to 01ad858492)
Solutions
- Connect a managed GitHub identity for the company/responsible user via the Apps catalog GitHub connection flow before dispatching the tool call.
- Verify the responsibleUserId on the session actually has a linked GitHub grant; re-link if it was revoked.
- If delegation is appropriate, allow standing delegation in resolveManagedGitHubIdentitySelection or grant the agent its own identity.
- Check the message body for the underlying selected.error detail to distinguish 'not connected' from 'connected but not selectable'.
- Return a clear operator action in the UI: prompt the responsible user to connect GitHub under Apps.
Example fix
// before
const res = await gateway.call(session, "github_list_issues", args); // throws 409
// after
const sel = await resolveManagedGitHubIdentitySelection(db, session.companyId, { agentId: session.agentId, responsibleUserId: session.responsibleUserId, allowStandingDelegation: false });
if (!sel.grant) throw new Error(`Connect GitHub first: ${sel.error}`);
const res = await gateway.call(session, "github_list_issues", args); Defensive patterns
Strategy: validation
When it happens
Trigger: An agent invokes a GitHub-backed tool via the gateway where toolConnections row has config.sourceTemplateKey (or transportConfig.sourceTemplateKey) === "github", and resolveManagedGitHubIdentitySelection returns no grant: no identity is connected for the responsible user, no agent-scoped grant exists, and allowStandingDelegation is false so delegation cannot substitute. selected.error is included in the message when present.
Common situations: Agent tries a GitHub tool before anyone connected GitHub in Apps/connections for that company; the responsible user changed to someone without a linked GitHub identity; a grant was revoked/deleted; org setup expects standing delegation but the call path passes allowStandingDelegation:false.
Related errors
- Managed GitHub connection is unavailable
- github_tool_unavailable
- grant_owner_membership_inactive
- ambiguous_personal_grant
- user_authorization_required
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/27e587293c85dcc0.
Report an issue: GitHub.