Slack Error Guide: 'no_such_subteam' — Fix User Group IDs
Fix the Slack no_such_subteam error: pass the usergroup S-prefixed ID not the @handle, list groups to resolve it, and use a user token with usergroups scopes.
- #slack
- #api
- #troubleshooting
- #errors
Stuck on this Slack error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
The no_such_subteam error is returned by the usergroups methods (usergroups.users.list, usergroups.users.update, usergroups.update, usergroups.enable, usergroups.disable) when the usergroup id you passed doesn’t correspond to a real user group in the workspace. In Slack’s API, user groups (the @team mentions) are historically called “subteams” and are identified by an id starting with S (for example S0123ABCD) — not by their @handle and not by their human name. Passing a handle, a name, a stale id, or an id from another workspace produces no_such_subteam.
Slack returns HTTP 200 with ok:false:
{
"ok": false,
"error": "no_such_subteam"
}
It occurs whenever the usergroup parameter is not a valid S… id visible to the token.
Symptoms
- usergroups calls fail with
no_such_subteamwhile the group is visible in the UI. - Passing
@oncalloroncallinstead of theS…id. - A hardcoded subteam id stops working after the group was deleted/recreated.
- Ids valid in one workspace fail in another on Enterprise Grid.
- Disabled user groups not found by an id you expected to work.
Common Root Causes
1. Using the handle or name instead of the S-id
The API needs the canonical subteam id (S…). The @handle and display name are not accepted.
2. A stale or deleted subteam id
If a user group was deleted and recreated, its id changed; the old id no longer resolves.
3. Cross-workspace id on Enterprise Grid
User groups can be workspace- or org-scoped; an id from a different workspace won’t resolve for this token.
4. Typo or truncated id
Copying an id from a URL or log and losing characters.
5. Token can’t see the group
The token’s workspace doesn’t contain that user group at all.
Diagnostic Workflow
Step 1: Reproduce the failure
curl -s -G "https://slack.com/api/usergroups.users.list" \
--data-urlencode "usergroup=@oncall" \
-H "Authorization: Bearer $SLACK_USER_TOKEN" | jq .error
"no_such_subteam"
Passing the handle @oncall fails — the API needs the S… id.
Step 2: List user groups to find the correct S-id
curl -s -G "https://slack.com/api/usergroups.list" \
--data-urlencode "include_disabled=true" \
-H "Authorization: Bearer $SLACK_USER_TOKEN" \
| jq -r '.usergroups[] | "\(.id)\t@\(.handle)\t\(.name)\tdisabled=\(.date_delete != 0)"'
S04ONCALL01 @oncall On-Call Engineers disabled=false
S05PLATFRM @platform Platform Team disabled=false
Map the handle to its S… id here.
Step 3: Call again with the S-id
curl -s -G "https://slack.com/api/usergroups.users.list" \
--data-urlencode "usergroup=S04ONCALL01" \
-H "Authorization: Bearer $SLACK_USER_TOKEN" \
| jq '{ok, users}'
{
"ok": true,
"users": ["U04ABCDE12", "U05FGHIJ34"]
}
Step 4: Validate the id shape before any write
echo "$USERGROUP_ID" | grep -Eq '^S[A-Z0-9]{6,}$' && echo "valid subteam id" || echo "NOT a subteam id"
NOT a subteam id
Guarding writes (like usergroups.users.update) behind this check avoids acting on the wrong thing.
Example Root Cause Analysis
An on-call sync job updates the @oncall user group’s membership each rotation. It reads the group by handle from config and fails:
curl -s -X POST https://slack.com/api/usergroups.users.update \
-H "Authorization: Bearer $SLACK_USER_TOKEN" -H "Content-Type: application/json" \
-d '{"usergroup":"oncall","users":"U04ABCDE12,U05FGHIJ34"}' | jq .error
"no_such_subteam"
The config stores the human handle oncall, but usergroups.users.update requires the S… id. The fix is to resolve the handle to its id via usergroups.list at run time and cache the mapping:
SID=$(curl -s "https://slack.com/api/usergroups.list" \
-H "Authorization: Bearer $SLACK_USER_TOKEN" \
| jq -r '.usergroups[] | select(.handle=="oncall") | .id')
curl -s -X POST https://slack.com/api/usergroups.users.update \
-H "Authorization: Bearer $SLACK_USER_TOKEN" -H "Content-Type: application/json" \
-d "{\"usergroup\":\"$SID\",\"users\":\"U04ABCDE12,U05FGHIJ34\"}" | jq .ok
true
Resolving the handle to its S… id makes the sync work reliably.
Prevention Best Practices
- Always pass the
S…subteam id, never the@handleor display name. - Resolve handles to ids at run time via
usergroups.list(withinclude_disabled=true) and cache the mapping with a TTL. - Validate the id shape (
^S…) before anyusergroups.*write to fail fast on bad config. - Remember usergroups methods require a user token with
usergroups:read/usergroups:write— a bot token often can’t manage groups. - On Enterprise Grid, be explicit about workspace- vs org-scoped groups and which workspace the token serves.
- For ad-hoc triage, the free incident assistant can map a handle to its subteam id from a failing sync. See more in Slack guides.
Quick Command Reference
# List all user groups (with ids and handles)
curl -s -G "https://slack.com/api/usergroups.list" \
--data-urlencode "include_disabled=true" \
-H "Authorization: Bearer $SLACK_USER_TOKEN" \
| jq -r '.usergroups[] | "\(.id)\t@\(.handle)\t\(.name)"'
# List members of a group by S-id
curl -s -G "https://slack.com/api/usergroups.users.list" \
--data-urlencode "usergroup=S04ONCALL01" \
-H "Authorization: Bearer $SLACK_USER_TOKEN" | jq '.users'
# Replace membership (full list!) by S-id
curl -s -X POST https://slack.com/api/usergroups.users.update \
-H "Authorization: Bearer $SLACK_USER_TOKEN" -H "Content-Type: application/json" \
-d '{"usergroup":"S04ONCALL01","users":"U1,U2,U3"}' | jq .ok
Conclusion
no_such_subteam means the usergroup id you supplied isn’t a valid user group for the token. The usual root causes:
- Passing the
@handleor name instead of theS…id. - A stale id for a deleted/recreated group.
- A cross-workspace id on Enterprise Grid.
- A typo or truncated id.
- A token whose workspace doesn’t contain the group.
Resolve handles to S… ids via usergroups.list at run time, validate the id shape before writes, and use a user token with the right usergroups scopes.
Fixed it? Get 500 Slack & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.