paperclipai/paperclip · error · ToolGatewayHttpError

github_identity_unavailable

github_identity_unavailable

Error message

${selected.error ?? "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.

Solutions

  1. Connect a managed GitHub identity for the company/responsible user via the Apps catalog GitHub connection flow before dispatching the tool call.
  2. Verify the responsibleUserId on the session actually has a linked GitHub grant; re-link if it was revoked.
  3. If delegation is appropriate, allow standing delegation in resolveManagedGitHubIdentitySelection or grant the agent its own identity.
  4. Check the message body for the underlying selected.error detail to distinguish 'not connected' from 'connected but not selectable'.
  5. 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


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/27e587293c85dcc0. Report an issue: GitHub.

Appendix: source

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

            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,

View on GitHub (pinned to 3f1d897a7c)