binarywang/WxJava · error · RuntimeException

请确保微信公众号配置 appId 的唯一性

Error message

请确保微信公众号配置 appId 的唯一性

What it means

Thrown by the Solon multi-account Official Account (公众号/MP) auto-configuration when two tenants share the same appId, to avoid Redis token/ticket cache corruption. The message is correct for the MP module; however the surrounding code references a variable named `wxCpMultiProperties` (a copy-paste artifact from the CP module) — functionally the validation still operates on the MP apps map.

Source

Thrown at solon-plugins/wx-java-mp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/mp_multi/configuration/services/AbstractWxMpConfiguration.java:54

    Map<String, WxMpSingleProperties> appsMap = wxCpMultiProperties.getApps();
    if (appsMap == null || appsMap.isEmpty()) {
      log.warn("微信公众号应用参数未配置,通过 WxMpMultiServices#getWxMpService(\"tenantId\")获取实例将返回空");
      return new WxMpMultiServicesImpl();
    }
    /**
     * 校验 appId 是否唯一,避免使用 redis 缓存 token、ticket 时错乱。
     *
     * 查看 {@link me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl#setAppId(String)}
     */
    Collection<WxMpSingleProperties> apps = appsMap.values();
    if (apps.size() > 1) {
      // 校验 appId 是否唯一
      boolean multi = apps.stream()
        // 没有 appId,如果不判断是否为空,这里会报 NPE 异常
        .collect(Collectors.groupingBy(c -> c.getAppId() == null ? 0 : c.getAppId(), Collectors.counting()))
        .entrySet().stream().anyMatch(e -> e.getValue() > 1);
      if (multi) {
        throw new RuntimeException("请确保微信公众号配置 appId 的唯一性");
      }
    }
    WxMpMultiServicesImpl services = new WxMpMultiServicesImpl();

    Set<Map.Entry<String, WxMpSingleProperties>> entries = appsMap.entrySet();
    for (Map.Entry<String, WxMpSingleProperties> entry : entries) {
      String tenantId = entry.getKey();
      WxMpSingleProperties wxMpSingleProperties = entry.getValue();
      WxMpDefaultConfigImpl storage = this.wxMpConfigStorage(wxCpMultiProperties);
      this.configApp(storage, wxMpSingleProperties);
      this.configHttp(storage, wxCpMultiProperties.getConfigStorage());
      this.configHost(storage, wxCpMultiProperties.getHosts());
      WxMpService wxCpService = this.wxMpService(storage, wxCpMultiProperties);
      services.addWxMpService(tenantId, wxCpService);
    }
    return services;
  }

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Confirm you are editing the MP (`wxjava.mp.apps`) config.
  2. Assign each tenant a unique Official Account `appId`.
  3. Fill blank appIds; restart the Solon app.

Example fix

// before
wxjava:
  mp:
    apps:
      a: { appId: wxmp001 }
      b: { appId: wxmp001 }  # duplicate -> throws
// after
      b: { appId: wxmp002 }
Defensive patterns

Strategy: validation

Validate before calling

// MP (Official Account): validate appId uniqueness
Set<String> seen = new HashSet<>();
for (WxMpSingleProperties p : appsMap.values()) {
    String id = p.getAppId();
    if (id == null || !seen.add(id)) {
        throw new IllegalStateException("MP appId missing or duplicated: " + id);
    }
}

Prevention

When it happens

Trigger: Two entries under `wxjava.mp.apps.*` with the same `appId`, or two entries with null appId collapsed to key `0`.

Common situations: Reusing one Official Account appId across tenant blocks; templated configs where appId was not substituted; misreading the odd `wxCpMultiProperties` variable name and suspecting a CP misconfiguration.

Related errors


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