{"record":{"id":"b69e486794d4f292","repo":"mastra-ai/mastra","slug":"agent-agentid-is-already-connected-to-slack","errorCode":null,"errorMessage":"Agent \"${agentId}\" is already connected to Slack. Disconnect first to reconnect.","messagePattern":"Agent \"(.+?)\" is already connected to Slack\\. Disconnect first to reconnect\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/slack/src/provider.ts","lineNumber":1116,"sourceCode":"            );\n          }\n          console.log(`[Slack] Reusing existing pending installation for \"${agentId}\"`);\n          return {\n            type: 'oauth' as const,\n            installationId: decrypted.id,\n            authorizationUrl: decrypted.authorizationUrl,\n          };\n        }\n      } catch {\n        // Corrupt pending record — delete it and create a fresh one\n        console.warn(`[Slack] Corrupt pending installation for \"${agentId}\", replacing it`);\n        await storage.deleteInstallation(existingRecord.id);\n      }\n    }\n\n    // If already connected, throw rather than creating a second app\n    if (existingRecord?.status === 'active') {\n      throw new Error(`Agent \"${agentId}\" is already connected to Slack. Disconnect first to reconnect.`);\n    }\n\n    const config = options ?? {};\n\n    // Generate unique webhook ID for this installation\n    const webhookId = crypto.randomUUID();\n\n    // Build manifest using the manifest builder (includes proper default scopes)\n    const appName = config.name ?? agent?.name ?? agentId;\n    const appDescription = config.description || agent?.getDescription() || 'AI assistant powered by Mastra';\n    const normalizedCommands = this.#normalizeCommands(config.slashCommands);\n    let manifest = buildManifest({\n      name: appName,\n      description: appDescription,\n      webhookUrl: `${baseUrl}/slack/events/${webhookId}`,\n      oauthRedirectUrl: `${baseUrl}/slack/oauth/callback`,\n      commandsUrl: `${baseUrl}/slack/commands/${webhookId}`,\n      slashCommands: normalizedCommands.map(cmd => ({","sourceCodeStart":1098,"sourceCodeEnd":1134,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/slack/src/provider.ts#L1098-L1134","documentation":"connect() checks stored installations and refuses to create a second Slack app for an agent whose existing installation record has status 'active'. Reconnecting requires an explicit disconnect, preventing duplicate apps and dangling webhook configurations.","triggerScenarios":"Calling connect(agentIdOrOptions) for an agent whose installation record in storage already has status === 'active' (previously connected and not disconnected).","commonSituations":"Re-running a connect script after a successful earlier run; retry logic blindly retrying connect after a partial failure; redeployments that re-invoke connect on boot; environment reuse sharing the same storage database.","solutions":["Call await provider.disconnect(agentId) first, then reconnect.","If the record is stale (app deleted in Slack), remove the installation record from storage (storage.deleteInstallation(id)) and reconnect.","Make connect calls idempotent in your boot code by checking connection status before calling connect."],"exampleFix":"// before\nawait provider.connect('support-agent'); // throws if already active\n// after\nconst status = await provider.getConnectionStatus('support-agent');\nif (status !== 'active') {\n  await provider.connect('support-agent');\n}","handlingStrategy":"try-catch","validationCode":"const existing = await provider.getConnectionStatus?.(agentId);\nif (existing === 'active') {\n  return; // already connected, skip connect\n}","typeGuard":null,"tryCatchPattern":"try {\n  await provider.connect(agentId);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('already connected to Slack')) {\n    // idempotent reconnect: disconnect then reconnect, or just ignore\n    await provider.disconnect(agentId);\n    await provider.connect(agentId);\n  } else throw err;\n}","preventionTips":["Make connect-on-boot idempotent by checking installation status first.","Never blind-retry connect() after a success; track completion state in your own job store.","Disconnect explicitly when removing or recreating a Slack app for an agent."],"tags":["state-conflict","duplicate","slack"],"backgroundTag":"already-connected","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}