multica-ai/multica · warning · ErrInvalidBotToken
slack: bot token must start with xoxb-
Error message
slack: bot token must start with xoxb-
What it means
Slack BYO (bring-your-own-app) validation error: the pasted bot token does not start with the required xoxb- prefix. RegisterBYO returns it before any network call; the handler maps it to 400 so the admin's dialog can show a precise hint.
Source
Thrown at server/internal/integrations/slack/byo_install.go:23
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"github.com/jackc/pgx/v5/pgtype"
"github.com/slack-go/slack"
db "github.com/multica-ai/multica/server/pkg/db/generated"
)
// ErrInvalidBotToken / ErrInvalidAppToken are returned by RegisterBYO when a
// pasted token is malformed (wrong prefix, or an app token whose app id cannot
// be parsed). The handler maps them to 400 so the dialog can show a precise hint
// instead of a generic failure.
var (
ErrInvalidBotToken = errors.New("slack: bot token must start with xoxb-")
ErrInvalidAppToken = errors.New("slack: app-level token must start with xapp- and embed an app id")
// ErrTokenAppMismatch is returned when the pasted bot token and app-level
// token belong to DIFFERENT Slack apps. Persisting that pair would "connect"
// but be broken: inbound arrives on the app token's socket (routed by its
// app id) while mention detection + outbound use the bot token's identity.
ErrTokenAppMismatch = errors.New("slack: the bot token and app-level token are from different Slack apps")
)
// RegisterBYOParams are the inputs for a bring-your-own-app install: the agent
// this bot represents, who is installing, and the two tokens the user pasted
// from their own Slack app.
type RegisterBYOParams struct {
WorkspaceID pgtype.UUID
AgentID pgtype.UUID
InitiatorID pgtype.UUID
BotToken string // xoxb-… — outbound Web API (chat.postMessage)
AppToken string // xapp-… — this app's OWN Socket Mode connection (inbound)
}View on GitHub (pinned to 2c0912b6ec)
Solutions
- Copy the Bot User OAuth Token (starts with xoxb-) from the Slack app's OAuth & Permissions page and re-paste.
- Trim whitespace/newlines from the pasted value before submitting.
- If you only have an xapp- value in hand, you copied the App-Level Token — keep looking for the bot token; do not paste it into this field.
Example fix
// before
err := svc.RegisterBYO(ctx, params) // params.BotToken = "xapp-..."
// -> "slack: bot token must start with xoxb-"
// after: validate at the edge, give a field-level hint
params.BotToken = strings.TrimSpace(params.BotToken)
if !strings.HasPrefix(params.BotToken, "xoxb-") {
return respondFieldError(w, "botToken", "must be a bot token starting with xoxb-")
}
err := svc.RegisterBYO(ctx, params) Defensive patterns
Strategy: validation
Validate before calling
bot := strings.TrimSpace(params.BotToken)
if !strings.HasPrefix(bot, "xoxb-") {
return respondFieldError(w, "botToken", "must start with xoxb-")
}
_ = svc.RegisterBYO(ctx, params) Type guard
func isSlackBotToken(s string) bool {
s = strings.TrimSpace(s)
return strings.HasPrefix(s, "xoxb-") && len(s) > len("xoxb-")
} Try / catch
if err := svc.RegisterBYO(ctx, params); err != nil {
if errors.Is(err, slack.ErrInvalidBotToken) {
return respondFieldError(w, "botToken", "copy the Bot User OAuth Token (xoxb-...)")
}
return err
} Prevention
- Label the two token fields in the UI with their prefixes (xoxb-, xapp-) and validate client-side.
- Trim whitespace on paste; password managers often add newlines.
- Deep-link admins to the exact Slack admin pages for each token type.
When it happens
Trigger: Calling RegisterBYO with a BotToken that is not a bot token — typically a user token (xoxp-), an app-level token (xapp-), an old workspace token (xoxa/xoxs), or a copied-with-whitespace/garbled string.
Common situations: Admin copies the wrong token field from the Slack app config page (app-level token instead of bot token); token pasted with leading/trailing spaces or a newline; token truncated by a password manager.
Related errors
- slack: the bot token and app-level token are from different
- slack: this Slack app is already connected to a different Mu
- slack: this Slack app is already connected to another agent
- slack: this Slack app is connected to an archived agent in t
- cloud runtime fleet URL is not configured
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/ad3fdc916d54848e.
Report an issue: GitHub.