mattermost-community/focalboard · error
cannot add bot to team %s: %w
Error message
cannot add bot to team %s: %w
What it means
getDirectChannel first ensures the delivery bot is a member of the team by calling pd.api.CreateMember(teamID, botID); when that call fails the error is wrapped as 'cannot add bot to team %s'. The subsequent direct channel creation never runs. This is a permission/team-membership failure at the Mattermost API level.
Source
Thrown at server/services/notify/plugindelivery/subscription_deliver.go:71
return "", fmt.Errorf("cannot find user: %w", err)
}
channel, err := pd.getDirectChannel(teamID, user.Id, botID)
if err != nil || channel == nil {
return "", fmt.Errorf("cannot get direct channel: %w", err)
}
return channel.Id, nil
case model.SubTypeChannel:
return subscriberID, nil
default:
return "", ErrUnsupportedSubscriberType
}
}
func (pd *PluginDelivery) getDirectChannel(teamID string, userID string, botID string) (*mm_model.Channel, error) {
// first ensure the bot is a member of the team.
_, err := pd.api.CreateMember(teamID, botID)
if err != nil {
return nil, fmt.Errorf("cannot add bot to team %s: %w", teamID, err)
}
return pd.api.GetDirectChannelOrCreate(userID, botID)
}
View on GitHub (pinned to a84bbb65e3)
Solutions
- Confirm the bot user exists and is active, and that teamID is a valid team ID.
- Manually add the bot to the team or grant it the needed permissions so CreateMember succeeds idempotently.
- Check the plugin's bot access token configuration in Mattermost system console.
- Log/inspect the wrapped cause to distinguish 'already a member' from permission failures.
Defensive patterns
Strategy: validation
Validate before calling
// before delivery, check bot membership
bot, err := api.GetUser(botID)
if err != nil || bot.DeleteAt != 0 {
return fmt.Errorf("bot %s missing or deactivated", botID)
}
tm, _ := api.GetTeamMember(teamID, botID)
if tm == nil {
_, err = api.CreateMember(teamID, botID) // pre-provision
if err != nil {
return fmt.Errorf("pre-provision bot into team %s failed: %w", teamID, err)
}
} Try / catch
chID, err := deliverer.SubscriptionDeliverSlackAttachments(...)
if err != nil && strings.Contains(err.Error(), "cannot add bot to team") {
logger.Error("bot cannot join team; check bot config/permissions", "team", teamID, "err", err)
return // alert operator rather than retrying blindly
} Prevention
- Provision the bot into required teams during plugin setup instead of at delivery time.
- Validate the configured bot access token at startup.
- Alert on deactivated/deleted bot accounts.
When it happens
Trigger: Called from getDirectChannelID (DM subscriptions) or MentionDeliver; pd.api.CreateMember(teamID, botID) returns an error — the bot is already a member but the API errors, the bot is not allowed to join, teamID is invalid, or the bot account is deactivated.
Common situations: Bot not invited/configured for the team; bot token lacking 'join_team' permissions; team ID typo or team deleted; Mattermost plugin misconfiguration (bot access token pointing at the wrong bot); Mattermost version differences in CreateMember semantics.
Related errors
- cannot get direct channel: %w
- ErrorId.TeamUndefined
- category doesn't belong to user
- cannot leave a board with no admins
- mention not permitted
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/f6d8717cc40f1f22.
Report an issue: GitHub.