{"record":{"id":"4034ef28810ddf73","repo":"paperclipai/paperclip","slug":"connector-refresh-failed","errorCode":"connector_refresh_failed","errorMessage":"Managed authorization could not be refreshed","messagePattern":"Managed authorization could not be refreshed","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":502,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":2854,"sourceCode":"          .returning();\n        if (!updated) {\n          throw new ToolGatewayHttpError(409, \"Managed authorization is no longer active\", \"connector_reauthorization_required\", {\n            connectionId: connection.id,\n            grantId: grant.id,\n          });\n        }\n        return updated;\n      } catch (error) {\n        if (error instanceof ToolGatewayHttpError) throw error;\n        if (error instanceof PaperclipCloudConnectorError && error.code === \"REAUTHORIZATION_REQUIRED\") {\n          await db.update(connectionGrants).set({ status: \"needs_reauthorization\", updatedAt: new Date(options.now?.() ?? Date.now()) })\n            .where(eq(connectionGrants.id, grant.id));\n          throw new ToolGatewayHttpError(409, \"Managed authorization must be reconnected\", \"connector_reauthorization_required\", {\n            connectionId: connection.id,\n            grantId: grant.id,\n          });\n        }\n        throw new ToolGatewayHttpError(502, \"Managed authorization could not be refreshed\", \"connector_refresh_failed\", {\n          connectionId: connection.id,\n          grantId: grant.id,\n        });\n      }\n    })();\n    gmailRefreshFlights.set(grant.id, refresh);\n    try {\n      return await refresh;\n    } finally {\n      if (gmailRefreshFlights.get(grant.id) === refresh) gmailRefreshFlights.delete(grant.id);\n    }\n  }\n\n  async function resolveCredentialHeaders(\n    session: ToolGatewaySession, connection: typeof toolConnections.$inferSelect,\n    grant: typeof connectionGrants.$inferSelect, resolveOptions: { forceRefresh?: boolean } = {},\n  ): Promise<Record<string, string>> {\n    const tracked = session.identityContextId && (connection.config.sourceTemplateKey === \"github\"","sourceCodeStart":2836,"sourceCodeEnd":2872,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-gateway.ts#L2836-L2872","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the tool call after a short delay; the refresh flight is deduplicated per grant so retries coalesce","Check Paperclip Cloud service status and instance network egress","Inspect server logs for the underlying error wrapped before this 502","Verify the secrets backend is healthy and resolveGrantSecretValue succeeds for the refresh ref"],"exampleFix":"// before\nawait gateway.callTool(session, connId, p); // 502 on transient Cloud outage\n// after\ntry { await gateway.callTool(session, connId, p); }\ncatch (e) { if (e.code === \"connector_refresh_failed\") await retryWithBackoff(() => gateway.callTool(session, connId, p)); }","handlingStrategy":"retry","validationCode":"// Pre-check connectivity before calls in long jobs:\nif (!(await isCloudReachable())) throw new Error(\"Paperclip Cloud unreachable; deferring connector calls\");","typeGuard":"function isRefreshFailed(e: unknown): e is ToolGatewayHttpError {\n  return e instanceof ToolGatewayHttpError && e.code === \"connector_refresh_failed\";\n}","tryCatchPattern":"try { await gateway.callTool(session, connId, p); }\ncatch (e) {\n  if (e.code === \"connector_refresh_failed\") await retryWithBackoff(() => gateway.callTool(session, connId, p), { retries: 3 });\n  else throw e;\n}","preventionTips":["Add retries with backoff for 502-class connector failures","Monitor Cloud egress and secrets-backend health","Distinguish transient (retry) from permanent (reauth) codes in error handling","Alert on Cloud 5xx rates from instance logs"],"tags":["network","cloud","oauth","transient"],"backgroundTag":"upstream-api-error","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}