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 bot

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Verify network egress from the server to WeCom API endpoints (curl the probe URL directly), fix proxy/firewall/DNS, then retry.
  2. If throttled (45009/45033), wait before retrying — do not rotate the secret.
  3. 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

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


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