{"record":{"id":"d18c985fc4b155e8","repo":"paperclipai/paperclip","slug":"oauth-refresh-missing","errorCode":"oauth_refresh_missing","errorMessage":"OAuth credentials have expired and no refresh token is available","messagePattern":"OAuth credentials have expired and no refresh token is available","errorType":"http","errorClass":"HttpError","httpStatus":422,"severity":"error","filePath":"server/src/services/tool-access.ts","lineNumber":4792,"sourceCode":"      },\n    };\n  }\n\n  async function ensureRuntimeSlot(connection: typeof toolConnections.$inferSelect): Promise<ToolRuntimeSlot | null> {\n    if (connection.transport !== \"local_stdio\") return null;\n    const slotKey = `mcp:${connection.companyId}:${connection.id}`;\n    const [existing] = await db\n      .select()\n      .from(toolRuntimeSlots)\n      .where(and(eq(toolRuntimeSlots.companyId, connection.companyId), eq(toolRuntimeSlots.slotKey, slotKey)));\n    if (existing) return toRuntimeSlot(existing);\n    const [created] = await db.insert(toolRuntimeSlots).values({\n      companyId: connection.companyId,\n      applicationId: connection.applicationId,\n      connectionId: connection.id,\n      slotKey,\n      ownerScopeType: \"connection\",\n      ownerScopeId: connection.id,\n      runtimeKind: \"local_stdio\",\n      status: \"stopped\",\n      provider: \"paperclip\",\n      providerRef: `template:${String(connection.config.templateId)}`,\n      commandTemplateKey: String(connection.config.templateId),\n      healthStatus: \"unchecked\",\n      metadata: { templateId: connection.config.templateId },\n    }).returning();\n    return toRuntimeSlot(created);\n  }\n\n  async function vaultGrantForConnection(\n    connection: typeof toolConnections.$inferSelect,\n    actor?: ActorInfo,\n  ): Promise<typeof connectionGrants.$inferSelect | null> {\n    const actorUserId = actor?.actorType === \"user\" ? actor.actorId ?? null : null;\n    if (actorUserId) {\n      const [personal] = await db.select().from(connectionGrants).where(and(","sourceCodeStart":4774,"sourceCodeEnd":4810,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/tool-access.ts#L4774-L4810","documentation":"Terminal credential guard in the OAuth refresh path: the stored token is expired (or the expired marker applies) and the connection has no refresh token, so renewal is impossible without user action. The user must reconnect the app; the connection's absent refresh token is at fault.","triggerScenarios":"Thrown at server/src/services/tool-access.ts:4634 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["No refresh token is stored, so expired credentials cannot be renewed. Reconnect the app to obtain fresh credentials."],"exampleFix":null,"handlingStrategy":"fallback","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-14T00:17:10.932Z"}