binarywang/WxJava · error · WxRuntimeException

微信服务端异常,超出重试次数

Error message

微信服务端异常,超出重试次数

What it means

Thrown by the Channel service when every configured retry for a WeChat API call has been exhausted. The execute0 loop only retries on WeChat error code -1 (系统繁忙 / system busy) using exponential backoff (retrySleepMillis * 2^attempt); once attempts exceed maxRetryTimes it gives up. Note line 217 wraps the failure in an UNCHECKED WxRuntimeException, whereas the inner guard at line 194 throws a checked WxErrorException — so a caller catching only WxErrorException can miss this terminal throw.

Source

Thrown at weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java:217

        WxError error = e.getError();
        // -1 系统繁忙, 1000ms后重试
        if (error.getErrorCode() == -1) {
          int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
          try {
            log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
            Thread.sleep(sleepMillis);
          } catch (InterruptedException e1) {
            Thread.currentThread().interrupt();
          }
        } else {
          throw e;
        }
      }
    } while (retryTimes++ < this.maxRetryTimes);

    log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
    throw new WxRuntimeException("微信服务端异常,超出重试次数");
  }

  protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefreshToken,
                                     boolean printResult) throws WxErrorException {
    E dataForLog = DataUtils.handleDataWithSecret(data);

    if (uri.contains("access_token=")) {
      throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
    }
    String accessToken = getAccessToken(false);

    WxChannelConfig config = this.getConfig();
    if (StringUtils.isNotEmpty(config.getApiHostUrl())) {
      uri = uri.replace("https://api.weixin.qq.com", config.getApiHostUrl());
    }

    String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken;

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Check WeChat platform status / 公告 for ongoing incidents before assuming a code problem.
  2. Raise maxRetryTimes and retrySleepMillis on the WxChannelService config so the loop tolerates longer busy windows.
  3. Wrap the call in an outer circuit-breaker/fallback (e.g. Resilience4j) with a longer total backoff than the inner loop allows.
  4. If the operation is non-critical, degrade to a cached or default response and surface a softer error to end users.

Example fix

// before
WxChannelService service = new WxChannelServiceImpl();
// default retry config, fails fast on sustained -1

// after
service.setMaxRetryTimes(5);
service.setRetrySleepMillis(2000); // 2s base, exponential
// plus outer guard:
try {
  return service.someApiCall(...);
} catch (WxRuntimeException | WxErrorException e) {
  log.warn("WeChat busy after retries, degrading", e);
  return cachedOrFallback();
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return channelService.someApiCall(req);
} catch (WxRuntimeException | WxErrorException e) {
  // line 217 throws unchecked WxRuntimeException; line 194 throws checked WxErrorException
  log.warn("WeChat busy after {} retries, degrading", channelService.getMaxRetryTimes(), e);
  return cachedOrFallback();
}

Prevention

When it happens

Trigger: WeChat's API returns errcode=-1 on every single retry attempt within execute0; the do-while loop runs out of attempts (retryTimes reaches maxRetryTimes) without ever getting a non-(-1) response or a success.

Common situations: WeChat platform outage or scheduled maintenance; aggressive rate-limiting surfaced as -1; upstream network/proxy instability causing every attempt to surface the busy code; maxRetryTimes configured too low for a degraded platform window.

Related errors


AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14). Data as JSON: /api/errors/e1285574944614f1. Report an issue: GitHub.