paperclipai/paperclip · error · ToolGatewayHttpError

connector_refresh_failed

connector_refresh_failed

Error message

Managed authorization could not be refreshed

What it means

Generic failure path for managed Gmail token refresh: any error that is not a ToolGatewayHttpError or a REAUTHORIZATION_REQUIRED Cloud error becomes a 502 connector_refresh_failed, indicating the Cloud refresh call itself failed (network, unexpected Cloud response, malformed token response).

Source

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

          .returning();
        if (!updated) {
          throw new ToolGatewayHttpError(409, "Managed authorization is no longer active", "connector_reauthorization_required", {
            connectionId: connection.id,
            grantId: grant.id,
          });
        }
        return updated;
      } catch (error) {
        if (error instanceof ToolGatewayHttpError) throw error;
        if (error instanceof PaperclipCloudConnectorError && error.code === "REAUTHORIZATION_REQUIRED") {
          await db.update(connectionGrants).set({ status: "needs_reauthorization", updatedAt: new Date(options.now?.() ?? Date.now()) })
            .where(eq(connectionGrants.id, grant.id));
          throw new ToolGatewayHttpError(409, "Managed authorization must be reconnected", "connector_reauthorization_required", {
            connectionId: connection.id,
            grantId: grant.id,
          });
        }
        throw new ToolGatewayHttpError(502, "Managed authorization could not be refreshed", "connector_refresh_failed", {
          connectionId: connection.id,
          grantId: grant.id,
        });
      }
    })();
    gmailRefreshFlights.set(grant.id, refresh);
    try {
      return await refresh;
    } finally {
      if (gmailRefreshFlights.get(grant.id) === refresh) gmailRefreshFlights.delete(grant.id);
    }
  }

  async function resolveCredentialHeaders(
    session: ToolGatewaySession, connection: typeof toolConnections.$inferSelect,
    grant: typeof connectionGrants.$inferSelect, resolveOptions: { forceRefresh?: boolean } = {},
  ): Promise<Record<string, string>> {
    const tracked = session.identityContextId && (connection.config.sourceTemplateKey === "github"

View on GitHub (pinned to 01ad858492)

Solutions

  1. Retry the tool call after a short delay; the refresh flight is deduplicated per grant so retries coalesce
  2. Check Paperclip Cloud service status and instance network egress
  3. Inspect server logs for the underlying error wrapped before this 502
  4. Verify the secrets backend is healthy and resolveGrantSecretValue succeeds for the refresh ref

Example fix

// before
await gateway.callTool(session, connId, p); // 502 on transient Cloud outage
// after
try { await gateway.callTool(session, connId, p); }
catch (e) { if (e.code === "connector_refresh_failed") await retryWithBackoff(() => gateway.callTool(session, connId, p)); }
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check connectivity before calls in long jobs:
if (!(await isCloudReachable())) throw new Error("Paperclip Cloud unreachable; deferring connector calls");

Type guard

function isRefreshFailed(e: unknown): e is ToolGatewayHttpError {
  return e instanceof ToolGatewayHttpError && e.code === "connector_refresh_failed";
}

Try / catch

try { await gateway.callTool(session, connId, p); }
catch (e) {
  if (e.code === "connector_refresh_failed") await retryWithBackoff(() => gateway.callTool(session, connId, p), { retries: 3 });
  else throw e;
}

Prevention

When it happens

Trigger: resolveGrantSecretValue or the Cloud exchange throws an unexpected error — secrets backend unreachable, network failure to Paperclip Cloud, Cloud returns an unhandled error code, token response missing expected fields.

Common situations: Paperclip Cloud outage or 5xx; DNS/network egress blocked from the instance to Cloud; secrets store (KMS/DB) temporarily unavailable; Cloud API contract change returning an unrecognized error code.

Related errors


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