multica-ai/multica · warning
wecom_credentials_unverifiable
wecom_credentials_unverifiable
Error message
wecom: could not reach WeCom to verify this bot
What it means
WeCom credential probe error: the probe could not reach WeCom or got an answer it cannot attribute to the credentials — dial failure, handshake timeout, network down, or any non-zero WeCom error code NOT on the rejection whitelist (e.g. frequency/concurrency protections 45009, 45033). Deliberately distinct from rejection: blaming the credentials would push an admin to rotate a long-connection secret that was fine, and a rotated secret cannot be recovered.
Source
Thrown at server/internal/integrations/wecom/credential_probe.go:60
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, keep
// the stored credentials untouched, and say we could not verify.
//
// Codes only, never errmsg text: the message is human-facing Chinese prose
// that WeCom is free to reword.
var rejectionErrCodes = map[int]struct{}{
40001: {}, // 不合法的secret参数 — the secret does not match this botView on GitHub (pinned to 2c0912b6ec)
Solutions
- Verify network egress from the server to WeCom API endpoints (curl the probe URL directly), fix proxy/firewall/DNS, then retry.
- If throttled (45009/45033), wait before retrying — do not rotate the secret.
- Only treat credentials as wrong when ErrCredentialsRejected is returned; for this error, keep the pair and fix reachability.
Example fix
// before
err := probe.Check(ctx, botID, secret)
if err != nil {
rotateSecretPrompt(w) // WRONG: sends admin to rotate a good secret
}
// after
err := probe.Check(ctx, botID, secret)
if errors.Is(err, wecom.ErrCredentialsUnverifiable) {
// network/platform issue — never suggest rotating; the rotated secret is unrecoverable
respond(w, 502, "could not reach WeCom to verify — check network and retry later")
return
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight reachability so install fails fast with a clear cause
if err := probe.ReachWeCom(ctx, 3*time.Second); err != nil {
return respondBadGateway(w, "server cannot reach WeCom — fix egress before entering credentials")
} Try / catch
err := probe.Check(ctx, botID, secret)
if err != nil {
if errors.Is(err, wecom.ErrCredentialsUnverifiable) {
// transport/throttle — retry with backoff; NEVER suggest rotating the secret
return retryWithBackoff(ctx, probe.Check, botID, secret)
}
return err
} Prevention
- Never map this error to 'wrong credentials' UI copy — a rotated WeCom long-connection secret is unrecoverable.
- Space probe attempts out; 45009/45033 are frequency/concurrency protections, not verdicts.
- Verify server egress to WeCom endpoints as part of deployment checks.
When it happens
Trigger: Running the credential probe when the Multica server cannot reach WeCom endpoints (egress blocked, DNS, proxy), or when WeCom answers with a throttling/platform error (45009, 45033) instead of a credential verdict. The whitelist-plus-fail-closed design maps all of these here.
Common situations: Server behind a firewall without egress to WeCom; retrying the probe rapidly and tripping rate limits; transient WeCom-side outage; corporate proxy terminating the connection.
Related errors
- wecom_credentials_rejected
- Invalid desktop runtime config: ${field} must be a non-empty
- runtime local skill discovery failed
- wecom: binding token invalid or expired
- wecom: user id is already bound to a different user
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/9dee58808ac1bf71.
Report an issue: GitHub.