multica-ai/multica · error
wecom_credentials_rejected
wecom_credentials_rejected
Error message
wecom: WeCom rejected this bot id and secret
What it means
WeCom credential probe error: WeCom itself answered that the bot id + secret pair is invalid — wrong secret, a bot that no longer exists, or a bot whose API mode is off. Only WeCom global error codes on the documented rejection whitelist (document/path/90313) produce this; it is the answer an admin can act on.
Source
Thrown at server/internal/integrations/wecom/credential_probe.go:54
// refused, a rejected install has knocked a live bot offline for nothing.
// InstallationService.Upsert enforces this: it takes the slot's advisory lock,
// reads the current owner, and returns the conflict without probing for any
// live owner other than the caller's own row (see botSlotConflictErr). What
// reaches the probe is a free slot, a revoked row, an orphan, or a re-install
// of the caller's own bot — nothing anybody else is connected to.
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
)
// ErrCredentialsRejected is WeCom saying the pair is not valid: a wrong
// secret, a bot that no longer exists, a bot whose API mode is off. It is the
// answer that must reach the admin, because it is the one they can act on.
var ErrCredentialsRejected = errors.New("wecom: WeCom rejected this bot id and secret")
// ErrCredentialsUnverifiable is everything else — the dial failed, the
// handshake timed out, the network is down. Distinct from rejection on
// purpose: telling an admin their credentials are wrong when the deployment
// simply could not reach WeCom sends them to rotate a secret that was fine.
var ErrCredentialsUnverifiable = errors.New("wecom: could not reach WeCom to verify this bot")
// rejectionErrCodes are the WeCom global error codes (document/path/90313)
// documented as a refusal of the credential pair itself — the only answers
// entitled to tell an admin their Bot ID or secret is wrong.
//
// Everything else non-zero is ErrCredentialsUnverifiable, deliberately. WeCom
// only guarantees that 0 means success; the subscribe path is also under
// frequency and concurrency protection (45009, 45033), and the platform can
// fail on its own account. Reading any non-zero code as "wrong secret" pushes
// an admin to rotate a long-connection secret that was fine, and a rotated one
// cannot be recovered — the exact damage this file exists to prevent. So the
// list is a whitelist and the default is fail-closed: refuse the install, keepView on GitHub (pinned to 2c0912b6ec)
Solutions
- Re-copy both Bot ID and secret from the WeCom console (trim whitespace) and re-run the probe.
- Confirm the bot still exists and its API mode / long-connection capability is enabled in the WeCom admin console.
- If the secret was rotated, use the CURRENT value — old secrets stop working immediately after rotation.
Example fix
// before
err := probe.Check(ctx, botID, secret)
if err != nil {
installFailed(w, err) // shows generic failure
}
// after
err := probe.Check(ctx, botID, secret)
switch {
case errors.Is(err, wecom.ErrCredentialsRejected):
respond(w, 400, "WeCom rejected this bot id and secret — re-copy them and check API mode")
case errors.Is(err, wecom.ErrCredentialsUnverifiable):
respond(w, 502, "could not reach WeCom — check network, do NOT rotate the secret")
} Defensive patterns
Strategy: try-catch
Validate before calling
// cheap pre-check: trim inputs, confirm both are non-empty and well-formed
botID, secret = strings.TrimSpace(botID), strings.TrimSpace(secret)
if botID == "" || secret == "" {
return respondFieldError(w, "", "both bot id and secret are required")
} Try / catch
err := probe.Check(ctx, botID, secret)
if err != nil {
switch {
case errors.Is(err, wecom.ErrCredentialsRejected):
// admin-actionable: re-copy credentials / enable API mode; do not retry
return respondBadRequest(w, "WeCom rejected this bot id and secret")
case errors.Is(err, wecom.ErrCredentialsUnverifiable):
return respondBadGateway(w, "could not reach WeCom")
}
return err
} Prevention
- Trim whitespace on both fields before probing.
- After rotating a WeCom secret, update it everywhere immediately — old values fail with this error.
- Confirm the bot's API mode is enabled in WeCom before first connect.
When it happens
Trigger: Calling the credential probe during install with a secret that was rotated, a typo'd Bot ID, a deleted bot, or a bot for which the long-connection API mode was never enabled. WeCom returns a whitelisted rejection code, which the probe maps to ErrCredentialsRejected.
Common situations: Secret regenerated in the WeCom console after it was pasted; copied bot id vs secret swapped; admin created the bot but did not enable API mode; trailing whitespace in either field.
Related errors
- wecom_credentials_unverifiable
- Invalid desktop runtime config: ${field} must use http or ht
- Invalid desktop runtime config: ${field} must use ws or wss
- cloud runtime fleet URL is not configured
- repo is not configured for this workspace
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/64494cc0238e187e.
Report an issue: GitHub.