binarywang/WxJava · error · WxErrorException
X-APPID不能为空
Error message
X-APPID不能为空
What it means
Thrown by `executeDialogPost` when a dialog call is made with `withOpenToken=false` and neither the per-call `appid` argument nor `configStorage.appid` is set. The resolved appid (`defaultIfBlank(appid, configStorage.appid)`) is required for the `X-APPID` header. It is a WxErrorException.
Source
Thrown at weixin-java-aispeech/src/main/java/me/chanjar/weixin/aispeech/api/impl/WxAispeechServiceImpl.java:111
long timestamp = System.currentTimeMillis() / 1000;
String nonce = randomNonce();
String sign = WxAispeechSignUtil.calcDialogSign(configStorage.getToken(), timestamp, nonce, body);
String resolvedAppid = StringUtils.defaultIfBlank(appid, configStorage.getAppid());
HttpPost request = new HttpPost(configStorage.getDialogApiBaseUrl() + path);
request.setHeader("request_id", requestId);
request.setHeader("timestamp", String.valueOf(timestamp));
request.setHeader("nonce", nonce);
request.setHeader("sign", sign);
request.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
if (withOpenToken) {
if (StringUtils.isBlank(configStorage.getOpenAiToken())) {
throw new WxErrorException("X-OPENAI-TOKEN不能为空,请先调用getAccessToken或手动设置");
}
request.setHeader("X-OPENAI-TOKEN", configStorage.getOpenAiToken());
} else {
if (StringUtils.isBlank(resolvedAppid)) {
throw new WxErrorException("X-APPID不能为空");
}
request.setHeader("X-APPID", resolvedAppid);
}
request.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON));
return executeRequest(request);
}
protected String executeKnowledgeGet(String path, Map<String, String> queryParams) throws WxErrorException {
try {
URIBuilder builder = new URIBuilder(configStorage.getKnowledgeApiBaseUrl() + path);
if (queryParams != null) {
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
if (entry.getValue() != null) {
builder.addParameter(entry.getKey(), entry.getValue());
}
}
}
HttpGet request = new HttpGet(builder.build());View on GitHub (pinned to 1c43293a3c)
Solutions
- Set appid on the config storage at init: `configStorage.setAppid(...)`.
- Or pass a non-blank appid to the dialog method call.
- Validate configuration completeness before issuing requests.
Example fix
// before
String r = service.executeDialogPost(path, body, false, null); // throws
// after
configStorage.setAppid("your-appid");
String r = service.executeDialogPost(path, body, false, null); Defensive patterns
Strategy: validation
Validate before calling
// Ensure an appid is resolvable for non-OpenAI-token dialog calls
String resolvedAppid = StringUtils.defaultIfBlank(appid, configStorage.getAppid());
if (!withOpenToken && StringUtils.isBlank(resolvedAppid)) {
throw new IllegalStateException("No appid available for X-APPID header");
} Prevention
- Always set appid on the config storage at init.
- Pass an explicit appid when tenants differ per call.
- Add a config-completeness assertion at startup.
When it happens
Trigger: Calling a non-OpenAI-token dialog path while the global appid was never configured and no appid was passed to the method.
Common situations: Config storage created without setting appid; relying on a per-call appid but passing null; partial config after migrating setup code.
Related errors
- 知识助理请求需要配置appid
- 知识助理请求需要配置secretKey
- 响应为空
- X-OPENAI-TOKEN不能为空,请先调用getAccessToken或手动设置
- HmacSHA256 signature failed
AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14).
Data as JSON: /api/errors/f7113c5272fb0857.
Report an issue: GitHub.