{"record":{"id":"f778d2d4b1ace9d2","repo":"binarywang/WxJava","slug":"appid-f778d2","errorCode":null,"errorMessage":"请确保微信公众号配置 appId 的唯一性","messagePattern":"请确保微信公众号配置 appId 的唯一性","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"solon-plugins/wx-java-mp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/mp_multi/configuration/services/AbstractWxMpConfiguration.java","lineNumber":54,"sourceCode":"    Map<String, WxMpSingleProperties> appsMap = wxCpMultiProperties.getApps();\n    if (appsMap == null || appsMap.isEmpty()) {\n      log.warn(\"微信公众号应用参数未配置，通过 WxMpMultiServices#getWxMpService(\\\"tenantId\\\")获取实例将返回空\");\n      return new WxMpMultiServicesImpl();\n    }\n    /**\n     * 校验 appId 是否唯一，避免使用 redis 缓存 token、ticket 时错乱。\n     *\n     * 查看 {@link me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl#setAppId(String)}\n     */\n    Collection<WxMpSingleProperties> apps = appsMap.values();\n    if (apps.size() > 1) {\n      // 校验 appId 是否唯一\n      boolean multi = apps.stream()\n        // 没有 appId，如果不判断是否为空，这里会报 NPE 异常\n        .collect(Collectors.groupingBy(c -> c.getAppId() == null ? 0 : c.getAppId(), Collectors.counting()))\n        .entrySet().stream().anyMatch(e -> e.getValue() > 1);\n      if (multi) {\n        throw new RuntimeException(\"请确保微信公众号配置 appId 的唯一性\");\n      }\n    }\n    WxMpMultiServicesImpl services = new WxMpMultiServicesImpl();\n\n    Set<Map.Entry<String, WxMpSingleProperties>> entries = appsMap.entrySet();\n    for (Map.Entry<String, WxMpSingleProperties> entry : entries) {\n      String tenantId = entry.getKey();\n      WxMpSingleProperties wxMpSingleProperties = entry.getValue();\n      WxMpDefaultConfigImpl storage = this.wxMpConfigStorage(wxCpMultiProperties);\n      this.configApp(storage, wxMpSingleProperties);\n      this.configHttp(storage, wxCpMultiProperties.getConfigStorage());\n      this.configHost(storage, wxCpMultiProperties.getHosts());\n      WxMpService wxCpService = this.wxMpService(storage, wxCpMultiProperties);\n      services.addWxMpService(tenantId, wxCpService);\n    }\n    return services;\n  }\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/solon-plugins/wx-java-mp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/mp_multi/configuration/services/AbstractWxMpConfiguration.java#L36-L72","documentation":"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.","triggerScenarios":"Two entries under `wxjava.mp.apps.*` with the same `appId`, or two entries with null appId collapsed to key `0`.","commonSituations":"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.","solutions":["Confirm you are editing the MP (`wxjava.mp.apps`) config.","Assign each tenant a unique Official Account `appId`.","Fill blank appIds; restart the Solon app."],"exampleFix":"// before\nwxjava:\n  mp:\n    apps:\n      a: { appId: wxmp001 }\n      b: { appId: wxmp001 }  # duplicate -> throws\n// after\n      b: { appId: wxmp002 }","handlingStrategy":"validation","validationCode":"// MP (Official Account): validate appId uniqueness\nSet<String> seen = new HashSet<>();\nfor (WxMpSingleProperties p : appsMap.values()) {\n    String id = p.getAppId();\n    if (id == null || !seen.add(id)) {\n        throw new IllegalStateException(\"MP appId missing or duplicated: \" + id);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ignore the misnamed `wxCpMultiProperties` variable — the check is on MP apps.","Substitute appId in every templated tenant block.","Lint config keys in CI."],"tags":["config","multi-tenant","mp","official-account","solon","startup"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}