twentyhq/twenty · error · Error
No workspace has claimed Slack team ${teamId}. Connect the S
Error message
No workspace has claimed Slack team ${teamId}. Connect the Slack app in the target workspace first. What it means
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.
Source
Thrown at packages/twenty-apps/public/slack/src/logic-functions/utils/resolve-target-workspace-id.ts:23
import { getSlackTeamKvKey } from 'src/logic-functions/utils/get-slack-team-kv-key';
export const resolveTargetWorkspaceId = async (
body: SlackEventsRequestBody,
): Promise<string> => {
const teamId = body.team_id;
if (!isNonEmptyString(teamId)) {
throw new Error(
'Slack event has no team_id; cannot resolve the target workspace',
);
}
const claimedWorkspaceId = await kv.get<string>(getSlackTeamKvKey(teamId), {
scope: 'SERVER',
});
if (!isNonEmptyString(claimedWorkspaceId)) {
throw new Error(
`No workspace has claimed Slack team ${teamId}. Connect the Slack app in the target workspace first.`,
);
}
return claimedWorkspaceId;
};
View on GitHub (pinned to 1f5dd2bbd2)
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.
Example fix
// before
const claimedWorkspaceId = await kv.get<string>(getSlackTeamKvKey(teamId), { scope: 'SERVER' });
if (!isNonEmptyString(claimedWorkspaceId)) {
throw new Error(`No workspace has claimed Slack team ${teamId}. Connect the Slack app in the target workspace first.`);
}
// after — return a user-facing error response instead of throwing for unconnected teams
const claimedWorkspaceId = await kv.get<string>(getSlackTeamKvKey(teamId), { scope: 'SERVER' });
if (!isNonEmptyString(claimedWorkspaceId)) {
return {
text: `This Slack workspace (${teamId}) isn't connected to a Twenty workspace yet. Connect the Slack app in Twenty → Settings → Apps first.`,
response_type: 'ephemeral',
};
} Defensive patterns
Strategy: validation
Validate before calling
// Health check the Slack app can expose:
export const isSlackTeamClaimed = async (teamId: string): Promise<boolean> =>
isNonEmptyString(await kv.get<string>(getSlackTeamKvKey(teamId), { scope: 'SERVER' })); Type guard
const isClaimedWorkspaceId = (v: unknown): v is string => typeof v === 'string' && v.trim().length > 0;
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- upsertRowLevelPermissionPredicates returned fewer than 2 pre
- upsertRowLevelPermissionPredicates returned no predicate for
- Missing ${name} env var
- Missing ${name} env var
- createFileUpload mutation did not return an upload target
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/941d93308ac918fb.
Report an issue: GitHub.