multica-ai/multica · error · ErrInstallationNotFound

slack installation not found

Error message

slack installation not found

What it means

Slack ErrInstallationNotFound: no channel_installation row (channel_type='slack') matches the lookup in the given workspace. Sentinel exists so HTTP handlers return 404 without importing pgx; distinct from the ownership-collision errors raised during install.

Solutions

  1. Refresh the installation list via ListChannelInstallationsByWorkspace and address the current row.
  2. Verify the workspace_id parameter matches the workspace the Slack app was connected in.
  3. If the app was disconnected, run the BYO connect flow again to create a new installation.

Example fix

// before
inst, err := svc.Get(ctx, workspaceID, id)
if err != nil {
	return err
}

// after
inst, err := svc.Get(ctx, workspaceID, id)
if errors.Is(err, slack.ErrInstallationNotFound) {
	http.NotFound(w, r)
	return
}
Defensive patterns

Strategy: try-catch

Validate before calling

insts, _ := installSvc.List(ctx, workspaceID)
have := false
for _, i := range insts { if i.ID == wantID { have = true } }
if !have { return refreshList(w) }

Try / catch

inst, err := installSvc.Get(ctx, workspaceID, id)
if err != nil {
	if errors.Is(err, slack.ErrInstallationNotFound) {
		http.NotFound(w, r)
		return
	}
	return err
}

Prevention

When it happens

Trigger: Calling InstallService get/revoke with a (workspace_id, installation id or app id) pair with no matching row — wrong workspace, already-disconnected app, or a stale id held by the UI.

Common situations: Frontend holds a cached installation id after the admin disconnected the app in another tab; workspace-scoped lookup receives the installation's id from a different workspace; deleted/re-installed app leaves old references behind.

Related errors


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

Appendix: source

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

	"github.com/jackc/pgx/v5/pgconn"
	"github.com/jackc/pgx/v5/pgtype"

	"github.com/multica-ai/multica/server/internal/integrations/channel/engine"
	"github.com/multica-ai/multica/server/internal/util/secretbox"
	db "github.com/multica-ai/multica/server/pkg/db/generated"
)

// This file is the Slack install backend (MUL-3666). Slack uses the
// bring-your-own-app (BYO) model: the workspace admin creates their own Slack
// app, installs it to their Slack workspace, and pastes its bot token (xoxb-) +
// app-level token (xapp-) into Multica (the paste path lives in byo_install.go).
// The InstallService owns the at-rest encryption of those tokens — so no caller
// can write a channel_installation with a plaintext token — plus the shared
// persistInstall transaction and the list / get / revoke management surface.

var (
	// ErrInstallationNotFound surfaces "no row matches in this workspace".
	ErrInstallationNotFound = errors.New("slack installation not found")
	// ErrTeamOwnedByAnotherWorkspace is returned when the pasted Slack app is
	// already connected to a live owner in a DIFFERENT Multica workspace — it
	// would collide with the (channel_type, app_id) routing index. A Slack app is
	// one bot identity and maps to one agent; reusing it here requires
	// disconnecting it in the other workspace first.
	ErrTeamOwnedByAnotherWorkspace = errors.New("slack: this Slack app is already connected to a different Multica workspace")
	// ErrTeamOwnedBySameWorkspace is returned when the app is already connected to
	// a DIFFERENT (live, non-archived) agent in the SAME workspace. The old
	// catch-all wrongly blamed "another workspace"; naming the same-workspace case
	// points the user at the Disconnect they can actually reach (#4810).
	ErrTeamOwnedBySameWorkspace = errors.New("slack: this Slack app is already connected to another agent in this workspace")
	// ErrTeamOwnedByArchivedAgent is returned when the app's owning agent is
	// archived (and so still holds the bot, since archiving is reversible). The
	// user recovers by restoring that agent or disconnecting its bot.
	ErrTeamOwnedByArchivedAgent = errors.New("slack: this Slack app is connected to an archived agent in this workspace")
)

// installQueries is the slice of generated queries InstallService needs. WithTx

View on GitHub (pinned to 2c0912b6ec)