{"record":{"id":"e1285574944614f1","repo":"binarywang/WxJava","slug":"error-e12855","errorCode":null,"errorMessage":"微信服务端异常，超出重试次数","messagePattern":"微信服务端异常，超出重试次数","errorType":"exception","errorClass":"WxRuntimeException","httpStatus":null,"severity":"error","filePath":"weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java","lineNumber":217,"sourceCode":"\n        WxError error = e.getError();\n        // -1 系统繁忙, 1000ms后重试\n        if (error.getErrorCode() == -1) {\n          int sleepMillis = this.retrySleepMillis * (1 << retryTimes);\n          try {\n            log.warn(\"微信系统繁忙，{} ms 后重试(第{}次)\", sleepMillis, retryTimes + 1);\n            Thread.sleep(sleepMillis);\n          } catch (InterruptedException e1) {\n            Thread.currentThread().interrupt();\n          }\n        } else {\n          throw e;\n        }\n      }\n    } while (retryTimes++ < this.maxRetryTimes);\n\n    log.warn(\"重试达到最大次数【{}】\", this.maxRetryTimes);\n    throw new WxRuntimeException(\"微信服务端异常，超出重试次数\");\n  }\n\n  protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefreshToken,\n                                     boolean printResult) throws WxErrorException {\n    E dataForLog = DataUtils.handleDataWithSecret(data);\n\n    if (uri.contains(\"access_token=\")) {\n      throw new IllegalArgumentException(\"uri参数中不允许有access_token: \" + uri);\n    }\n    String accessToken = getAccessToken(false);\n\n    WxChannelConfig config = this.getConfig();\n    if (StringUtils.isNotEmpty(config.getApiHostUrl())) {\n      uri = uri.replace(\"https://api.weixin.qq.com\", config.getApiHostUrl());\n    }\n\n    String uriWithAccessToken = uri + (uri.contains(\"?\") ? \"&\" : \"?\") + \"access_token=\" + accessToken;\n","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java#L199-L235","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check WeChat platform status / 公告 for ongoing incidents before assuming a code problem.","Raise maxRetryTimes and retrySleepMillis on the WxChannelService config so the loop tolerates longer busy windows.","Wrap the call in an outer circuit-breaker/fallback (e.g. Resilience4j) with a longer total backoff than the inner loop allows.","If the operation is non-critical, degrade to a cached or default response and surface a softer error to end users."],"exampleFix":"// before\nWxChannelService service = new WxChannelServiceImpl();\n// default retry config, fails fast on sustained -1\n\n// after\nservice.setMaxRetryTimes(5);\nservice.setRetrySleepMillis(2000); // 2s base, exponential\n// plus outer guard:\ntry {\n  return service.someApiCall(...);\n} catch (WxRuntimeException | WxErrorException e) {\n  log.warn(\"WeChat busy after retries, degrading\", e);\n  return cachedOrFallback();\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return channelService.someApiCall(req);\n} catch (WxRuntimeException | WxErrorException e) {\n  // line 217 throws unchecked WxRuntimeException; line 194 throws checked WxErrorException\n  log.warn(\"WeChat busy after {} retries, degrading\", channelService.getMaxRetryTimes(), e);\n  return cachedOrFallback();\n}","preventionTips":["Tune maxRetryTimes and retrySleepMillis to tolerate WeChat maintenance windows.","Catch BOTH WxRuntimeException and WxErrorException — the exhausted-retry terminal is unchecked.","Put an outer circuit-breaker around WeChat calls during known outages."],"tags":["retry","wechat-server","channel","transient","rate-limit"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}