{"record":{"id":"388f2807d4c54f59","repo":"paperclipai/paperclip","slug":"oauth-access-token-missing","errorCode":"oauth_access_token_missing","errorMessage":"OAuth provider did not return an access token","messagePattern":"OAuth provider did not return an access token","errorType":"http","errorClass":"HttpError","httpStatus":502,"severity":"error","filePath":"server/src/services/tool-access.ts","lineNumber":4612,"sourceCode":"          .update(toolMcpGatewayTokens)\n          .set({ revokedAt: now, updatedAt: now })\n          .where(and(\n            eq(toolMcpGatewayTokens.companyId, connection.companyId),\n            inArray(toolMcpGatewayTokens.gatewayId, gatewayRows.map((row) => row.id)),\n            isNull(toolMcpGatewayTokens.revokedAt),\n          ))\n          .returning({ id: toolMcpGatewayTokens.id });\n        gatewayTokensRevoked = revokedTokens.length;\n        if (revokedTokens.length > 0) {\n          gatewaySessionsRevoked = (await db\n            .update(toolGatewaySessions)\n            .set({ revokedAt: now, updatedAt: now })\n            .where(and(\n              eq(toolGatewaySessions.companyId, connection.companyId),\n              inArray(toolGatewaySessions.gatewayTokenId, revokedTokens.map((row) => row.id)),\n              isNull(toolGatewaySessions.revokedAt),\n            ))\n            .returning({ id: toolGatewaySessions.id })).length;\n        }\n      }\n    }\n\n    // A local runtime already holds the injected credential inside a live child\n    // process, so archiving rows is not enough — the process itself is an access\n    // path. Stopping is best effort on purpose: if the supervisor cannot be\n    // reached, revoking the credential anyway (so nothing can start again) beats\n    // abandoning the teardown, and the warning says which slot was left running.\n    let runtimeSlotsStopped = 0;\n    const runtimeSlotRows = await db\n      .select({ id: toolRuntimeSlots.id, status: toolRuntimeSlots.status })\n      .from(toolRuntimeSlots)\n      .where(and(\n        eq(toolRuntimeSlots.companyId, connection.companyId),\n        eq(toolRuntimeSlots.connectionId, connection.id),\n      ));\n    for (const slot of runtimeSlotRows) {","sourceCodeStart":4594,"sourceCodeEnd":4630,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-access.ts#L4594-L4630","documentation":"The OAuth token exchange response body contained no access_token field, so despite the provider responding, no usable credential was obtained and the exchange is treated as failed.","triggerScenarios":"Thrown at server/src/services/tool-access.ts:4454 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The provider response contained no access token. Check the provider configuration/scopes and retry the authorization."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}