binarywang/WxJava · error · WxErrorException
通讯录同步secret未配置
Error message
通讯录同步secret未配置
What it means
Thrown (as checked WxErrorException) by getContactAccessToken() in the Apache HttpClient implementation when the contact-sync secret (通讯录同步secret) is null or blank. This secret is required to obtain a separate access_token for contact-sync API calls, distinct from the main corp secret.
Source
Thrown at weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java:94
}
@Override
public String getContactAccessToken(boolean forceRefresh) throws WxErrorException {
if (!this.configStorage.isContactAccessTokenExpired() && !forceRefresh) {
return this.configStorage.getContactAccessToken();
}
Lock lock = this.configStorage.getContactAccessTokenLock();
lock.lock();
try {
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
if (!this.configStorage.isContactAccessTokenExpired() && !forceRefresh) {
return this.configStorage.getContactAccessToken();
}
// 使用通讯录同步secret获取access_token
String contactSecret = this.configStorage.getContactSecret();
if (contactSecret == null || contactSecret.trim().isEmpty()) {
throw new WxErrorException("通讯录同步secret未配置");
}
String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
this.configStorage.getCorpId(), contactSecret);
try {
HttpGet httpGet = new HttpGet(url);
if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom()
.setProxy(this.httpProxy).build();
httpGet.setConfig(config);
}
String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
WxError error = WxError.fromJson(resultContent, WxType.CP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);View on GitHub (pinned to 1c43293a3c)
Solutions
- Set the contact secret via configStorage.setContactSecret("your-contact-sync-secret") during initialization
- In Spring Boot starter, set wx.cp.contact-secret in application.yml
- Ensure the secret value comes from a reliable source (env var, config center) that is present in all environments
- Verify the secret is the 通讯录同步 secret from the WeChat Work admin console, not the main application secret
Example fix
// before
WxCpConfigStorage config = new WxCpDefaultConfigImpl();
config.setCorpId("corp123");
config.setCorpSecret("app-secret");
// contactSecret never set → getContactAccessToken fails
// after
WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
config.setCorpId("corp123");
config.setCorpSecret("app-secret");
config.setContactSecret(System.getenv("WX_CP_CONTACT_SECRET")); Defensive patterns
Strategy: validation
Validate before calling
// Validate contact secret is configured at startup
String contactSecret = configStorage.getContactSecret();
if (StringUtils.isBlank(contactSecret)) {
throw new IllegalStateException("启动检查失败:通讯录同步 secret 未配置,请在企业微信管理后台获取并设置 contactSecret");
} Prevention
- Set all three secrets (corpSecret, contactSecret, msgAuditSecret) during application initialization
- Use environment variables or a config center, not hardcoded values
- Add a startup health check that validates all required secrets are non-blank
- For Spring Boot starter, configure wx.cp.contact-secret in application.yml
When it happens
Trigger: Calling any method that triggers getContactAccessToken(true) — typically contact/department/user sync operations — when configStorage.getContactSecret() returns null or an empty/whitespace string.
Common situations: The WxCpConfigStorage was initialized without calling setContactSecret(); the secret was set from an environment variable that is not defined in the current deployment; the secret was cleared during a config refresh; using a config storage that does not persist the contact secret across restarts.
Related errors
AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14).
Data as JSON: /api/errors/c00319f09c017700.
Report an issue: GitHub.