{"record":{"id":"ad3fdc916d54848e","repo":"multica-ai/multica","slug":"slack-bot-token-must-start-with-xoxb","errorCode":null,"errorMessage":"slack: bot token must start with xoxb-","messagePattern":"slack: bot token must start with xoxb-","errorType":"http","errorClass":"ErrInvalidBotToken","httpStatus":400,"severity":"warning","filePath":"server/internal/integrations/slack/byo_install.go","lineNumber":23,"sourceCode":"\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/jackc/pgx/v5/pgtype\"\n\t\"github.com/slack-go/slack\"\n\n\tdb \"github.com/multica-ai/multica/server/pkg/db/generated\"\n)\n\n// ErrInvalidBotToken / ErrInvalidAppToken are returned by RegisterBYO when a\n// pasted token is malformed (wrong prefix, or an app token whose app id cannot\n// be parsed). The handler maps them to 400 so the dialog can show a precise hint\n// instead of a generic failure.\nvar (\n\tErrInvalidBotToken = errors.New(\"slack: bot token must start with xoxb-\")\n\tErrInvalidAppToken = errors.New(\"slack: app-level token must start with xapp- and embed an app id\")\n\t// ErrTokenAppMismatch is returned when the pasted bot token and app-level\n\t// token belong to DIFFERENT Slack apps. Persisting that pair would \"connect\"\n\t// but be broken: inbound arrives on the app token's socket (routed by its\n\t// app id) while mention detection + outbound use the bot token's identity.\n\tErrTokenAppMismatch = errors.New(\"slack: the bot token and app-level token are from different Slack apps\")\n)\n\n// RegisterBYOParams are the inputs for a bring-your-own-app install: the agent\n// this bot represents, who is installing, and the two tokens the user pasted\n// from their own Slack app.\ntype RegisterBYOParams struct {\n\tWorkspaceID pgtype.UUID\n\tAgentID     pgtype.UUID\n\tInitiatorID pgtype.UUID\n\tBotToken    string // xoxb-… — outbound Web API (chat.postMessage)\n\tAppToken    string // xapp-… — this app's OWN Socket Mode connection (inbound)\n}","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/integrations/slack/byo_install.go#L5-L41","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nerr := svc.RegisterBYO(ctx, params) // params.BotToken = \"xapp-...\"\n// -> \"slack: bot token must start with xoxb-\"\n\n// after: validate at the edge, give a field-level hint\nparams.BotToken = strings.TrimSpace(params.BotToken)\nif !strings.HasPrefix(params.BotToken, \"xoxb-\") {\n\treturn respondFieldError(w, \"botToken\", \"must be a bot token starting with xoxb-\")\n}\nerr := svc.RegisterBYO(ctx, params)","handlingStrategy":"validation","validationCode":"bot := strings.TrimSpace(params.BotToken)\nif !strings.HasPrefix(bot, \"xoxb-\") {\n\treturn respondFieldError(w, \"botToken\", \"must start with xoxb-\")\n}\n_ = svc.RegisterBYO(ctx, params)","typeGuard":"func isSlackBotToken(s string) bool {\n\ts = strings.TrimSpace(s)\n\treturn strings.HasPrefix(s, \"xoxb-\") && len(s) > len(\"xoxb-\")\n}","tryCatchPattern":"if err := svc.RegisterBYO(ctx, params); err != nil {\n\tif errors.Is(err, slack.ErrInvalidBotToken) {\n\t\treturn respondFieldError(w, \"botToken\", \"copy the Bot User OAuth Token (xoxb-...)\")\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["slack","byo","token-validation","configuration","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}