{"record":{"id":"0ed7d7feea3c4e52","repo":"multica-ai/multica","slug":"wecom-bot-owned-by-another-workspace","errorCode":"wecom_bot_owned_by_another_workspace","errorMessage":"wecom: this bot is already connected to a different Multica workspace","messagePattern":"wecom: this bot is already connected to a different Multica workspace","errorType":"exception","errorClass":null,"httpStatus":409,"severity":"error","filePath":"server/internal/integrations/wecom/installation.go","lineNumber":310,"sourceCode":"// a second agent misses the ON CONFLICT clause entirely and trips the index\n// instead. Without these the admin reads the raw Postgres text\n// (\"duplicate key value violates unique constraint …\") in a toast.\n//\n// One bot is one connection: the WeCom long connection allows a single\n// live subscriber per bot, so two agents cannot share one. The way out is\n// always to free the bot first, which is what each message says.\nvar (\n\t// ErrBotOwnedBySameWorkspace — another agent in the admin's own workspace\n\t// holds the bot. Reversible from the same settings screen.\n\tErrBotOwnedBySameWorkspace = errors.New(\"wecom: this bot is already connected to another agent in this workspace\")\n\n\t// ErrBotOwnedByArchivedAgent — the holder is archived, so it does not show\n\t// up in the agent list and the bot looks free while it is not.\n\tErrBotOwnedByArchivedAgent = errors.New(\"wecom: this bot is connected to an archived agent in this workspace\")\n\n\t// ErrBotOwnedByAnotherWorkspace — the holder is out of sight entirely and\n\t// only someone with access there can release it.\n\tErrBotOwnedByAnotherWorkspace = errors.New(\"wecom: this bot is already connected to a different Multica workspace\")\n)\n\n// pgUniqueViolation is Postgres' unique_violation SQLSTATE.\nconst pgUniqueViolation = \"23505\"\n\n// botSlotConflictErr answers one question: may this install act on the\n// (wecom, bot_id) routing slot at all? It returns the sentinel to refuse with,\n// or nil to proceed. MUST be called inside the transaction holding\n// LockChannelInstallationAppIDSlot — outside it the answer is a guess that a\n// concurrent install or reconnect can invalidate before it is used.\n//\n// It is the gate in front of BOTH side effects Upsert can produce: the probe's\n// subscribe (which displaces whoever is connected to this bot at WeCom) and the\n// reclaim's hard delete (which takes the row and its bindings). A refusal here\n// costs the caller nothing and the current owner nothing.\n//\n// The classification mirrors ReclaimDeadChannelInstallationByAppID's own\n// definition of \"dead\", so the two cannot drift into disagreeing about which","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/integrations/wecom/installation.go#L292-L328","documentation":"Error \"wecom: this bot is already connected to a different Multica workspace\" thrown in multica-ai/multica.","triggerScenarios":"Thrown at server/internal/integrations/wecom/installation.go:310 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Disconnect the bot from the other workspace first, or use a different WeCom bot."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}