{"record":{"id":"941d93308ac918fb","repo":"twentyhq/twenty","slug":"no-workspace-has-claimed-slack-team-teamid-con","errorCode":null,"errorMessage":"No workspace has claimed Slack team ${teamId}. Connect the Slack app in the target workspace first.","messagePattern":"No workspace has claimed Slack team (.+?)\\. Connect the Slack app in the target workspace first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/twenty-apps/public/slack/src/logic-functions/utils/resolve-target-workspace-id.ts","lineNumber":23,"sourceCode":"import { getSlackTeamKvKey } from 'src/logic-functions/utils/get-slack-team-kv-key';\n\nexport const resolveTargetWorkspaceId = async (\n  body: SlackEventsRequestBody,\n): Promise<string> => {\n  const teamId = body.team_id;\n\n  if (!isNonEmptyString(teamId)) {\n    throw new Error(\n      'Slack event has no team_id; cannot resolve the target workspace',\n    );\n  }\n\n  const claimedWorkspaceId = await kv.get<string>(getSlackTeamKvKey(teamId), {\n    scope: 'SERVER',\n  });\n\n  if (!isNonEmptyString(claimedWorkspaceId)) {\n    throw new Error(\n      `No workspace has claimed Slack team ${teamId}. Connect the Slack app in the target workspace first.`,\n    );\n  }\n\n  return claimedWorkspaceId;\n};\n","sourceCodeStart":5,"sourceCodeEnd":30,"githubUrl":"https://github.com/twentyhq/twenty/blob/1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6/packages/twenty-apps/public/slack/src/logic-functions/utils/resolve-target-workspace-id.ts#L5-L30","documentation":"The Slack logic function resolves the target Twenty workspace by reading the `team_id` from the Slack event and looking up `kv.get(getSlackTeamKvKey(teamId), { scope: 'SERVER' })`. If no value is stored, no Twenty workspace has connected/claimed that Slack team, so the event cannot be routed and the handler throws. The claim is written when a workspace connects the Slack app, so absence means the connect step was never completed for this Slack team.","triggerScenarios":"A Slack event arrives from a `team_id` that was never connected to a Twenty workspace, was connected but the KV entry expired/was cleared, or the lookup uses a different scope/key than the connect step wrote.","commonSituations":"A user in a Slack workspace that hasn't installed/connected the Twenty Slack app posting a slash command or event; KV being flushed/reset; a key-formation mismatch between `getSlackTeamKvKey` at write time and read time after a refactor.","solutions":["In the target Twenty workspace, connect the Slack app (Settings → Apps → Slack) so the connect handler writes the `team_id → workspaceId` KV entry at server scope.","Confirm `getSlackTeamKvKey(teamId)` produces the same key at read and write time (no refactor changed the key format).","Verify the KV entry is stored at `scope: 'SERVER'` on both the connect and resolve paths.","If KV was reset, re-run the Slack connect flow in each workspace to repopulate the claim entries."],"exampleFix":"// before\nconst claimedWorkspaceId = await kv.get<string>(getSlackTeamKvKey(teamId), { scope: 'SERVER' });\nif (!isNonEmptyString(claimedWorkspaceId)) {\n  throw new Error(`No workspace has claimed Slack team ${teamId}. Connect the Slack app in the target workspace first.`);\n}\n\n// after — return a user-facing error response instead of throwing for unconnected teams\nconst claimedWorkspaceId = await kv.get<string>(getSlackTeamKvKey(teamId), { scope: 'SERVER' });\nif (!isNonEmptyString(claimedWorkspaceId)) {\n  return {\n    text: `This Slack workspace (${teamId}) isn't connected to a Twenty workspace yet. Connect the Slack app in Twenty → Settings → Apps first.`,\n    response_type: 'ephemeral',\n  };\n}","handlingStrategy":"validation","validationCode":"// Health check the Slack app can expose:\nexport const isSlackTeamClaimed = async (teamId: string): Promise<boolean> =>\n  isNonEmptyString(await kv.get<string>(getSlackTeamKvKey(teamId), { scope: 'SERVER' }));","typeGuard":"const isClaimedWorkspaceId = (v: unknown): v is string =>\n  typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":null,"preventionTips":["Always run the Slack connect flow in the workspace before expecting events to route.","Keep `getSlackTeamKvKey` byte-identical between the connect (write) and resolve (read) paths.","Store and read the claim at the same KV scope (SERVER).","After any KV reset, re-run the connect flow in each workspace."],"tags":["slack","configuration","kv","workspace-routing","integration"],"backgroundTag":null,"analyzedSha":"1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6","analyzedAt":"2026-08-12T15:37:27.593Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}