multica-ai/multica · error · ErrTokenAppMismatch

slack: the bot token and app-level token are from different…

Error message

slack: the bot token and app-level token are from different Slack apps

What it means

Slack BYO validation error: the pasted xoxb- bot token and xapp- app-level token belong to DIFFERENT Slack apps. Persisting such a pair would appear connected but be broken: inbound events arrive over the app token's Socket Mode connection (routed by its app id) while mention detection and outbound posting use the bot token's identity.

Solutions

  1. Open ONE Slack app's configuration and copy both tokens from that same app: Bot User OAuth Token (xoxb-) from OAuth & Permissions and App-Level Token (xapp-) from Basic Information.
  2. Delete the stale/duplicate app if it exists, so only one candidate remains to copy from.
  3. After re-copying, re-run RegisterBYO; the mismatch check passes only when both tokens embed the same app id.

Example fix

// before
params.BotToken = "xoxb-..." // app A
params.AppToken = "xapp-..." // app B
err := svc.RegisterBYO(ctx, params)
// -> "slack: the bot token and app-level token are from different Slack apps"

// after: pre-validate app id alignment in the handler
botAppID, appAppID := parseAppID(params.BotToken), parseAppID(params.AppToken)
if botAppID != "" && appAppID != "" && botAppID != appAppID {
	return respondError(w, 400, "both tokens must come from the same Slack app")
}
err := svc.RegisterBYO(ctx, params)
Defensive patterns

Strategy: validation

Validate before calling

botApp := appIDFromToken(params.BotToken)  // parses app id from xoxb- token
appApp := appIDFromToken(params.AppToken) // parses app id from xapp- token
if botApp != "" && appApp != "" && botApp != appApp {
	return respondError(w, 400, "both tokens must come from the same Slack app")
}
_ = svc.RegisterBYO(ctx, params)

Try / catch

if err := svc.RegisterBYO(ctx, params); err != nil {
	if errors.Is(err, slack.ErrTokenAppMismatch) {
		return respondError(w, 400, "bot token and app token are from different apps — copy both from ONE app")
	}
	return err
}

Prevention

When it happens

Trigger: Calling RegisterBYO where the app id embedded in the xapp- token does not match the app id of the xoxb- bot token — e.g. the admin created two Slack apps and copied the bot token from one and the app-level token from the other.

Common situations: Two similarly named apps in the Slack dashboard; regenerated tokens in a new app after following an outdated tutorial; copy/paste mix-up between browser tabs each open to a different app's credentials page.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/77ce86efeb928154. Report an issue: GitHub.

Appendix: source

Thrown at server/internal/integrations/slack/byo_install.go:29

	"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)
}

// RegisterBYO installs a user-supplied ("bring your own") Slack app for an agent.
// The user creates their own Slack app, installs it to their workspace, and
// pastes its bot token (xoxb-) + app-level token (xapp-). There is NO OAuth code
// exchange: we validate the bot token live via auth.test (which also yields the
// team id + bot user id), prove the bot + app tokens belong to the SAME app,

View on GitHub (pinned to 2c0912b6ec)