binarywang/WxJava · critical · WxRuntimeException

获取 suite token 失败

Error message

获取 suite token 失败

What it means

Thrown as WxRuntimeException when an IOException occurs during the OkHttp suite_access_token request. The underlying IOException is wrapped with a descriptive message. This fires when the HTTP call itself fails (network-level), as opposed to error 168 which fires when the call succeeds but returns a non-zero error code.

Source

Thrown at weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java:83

        MediaType.get("application/json; charset=utf-8"),
        jsonBody
      );

      // 构建 POST 请求
      Request request = new Request.Builder()
        .url(this.configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN)) // URL 不包含查询参数
        .post(requestBody) // 使用 POST 方法
        .build();

      String resultContent = null;
      try (Response response = client.newCall(request).execute()) {
        if (!response.isSuccessful()) {
          throw new IOException("Unexpected response code: " + response);
        }
        resultContent = response.body().string();
      } catch (IOException e) {
        log.error("获取 suite token 失败: {}", e.getMessage(), e);
        throw new WxRuntimeException("获取 suite token 失败", e);
      }

      WxError error = WxError.fromJson(resultContent, WxType.CP);
      if (error.getErrorCode() != 0) {
        throw new WxErrorException(error);
      }

      jsonObject = GsonParser.parse(resultContent);
      String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
      int expiresIn = jsonObject.get("expires_in").getAsInt();
      this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
    }
    return this.configStorage.getSuiteAccessToken();
  }

  @Override
  public void initHttp() {
    log.debug("WxCpServiceOkHttpImpl initHttp");

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Verify network connectivity: curl -v https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token
  2. Configure adequate OkHttp timeouts: new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build()
  3. Check firewall, proxy, and DNS settings for outbound HTTPS to qyapi.weixin.qq.com
  4. Implement retry at the caller level — getSuiteAccessToken does not retry on IOException
Defensive patterns

Strategy: retry

Validate before calling

// Verify network reachability before invoking suite token APIs
try (Socket socket = new Socket()) {
  socket.connect(new InetSocketAddress("qyapi.weixin.qq.com", 443), 5000);
} catch (IOException e) {
  throw new IllegalStateException("Cannot reach qyapi.weixin.qq.com — check network/proxy", e);
}

Try / catch

// Retry at caller level since getSuiteAccessToken does not retry on IOException
int attempts = 0;
while (true) {
  try {
    service.getSuiteAccessToken();
    break;
  } catch (WxRuntimeException e) {
    if (e.getCause() instanceof IOException && attempts++ < 3) {
      Thread.sleep(2000L * attempts);
      continue;
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: OkHttp client.execute() throws IOException: connection timeout to qyapi.weixin.qq.com, DNS resolution failure, TLS handshake failure, HTTP non-2xx response code (response.isSuccessful() returns false causing a manually thrown IOException).

Common situations: Firewall blocking outbound HTTPS; HTTP proxy misconfigured or unreachable; OkHttp client timeouts set too low; DNS resolution failure in containerized environments; WeChat API temporarily unreachable.

Related errors


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