{"record":{"id":"e9aae7bb9195a536","repo":"binarywang/WxJava","slug":"no-button-array-found-in-menu-json","errorCode":null,"errorMessage":"No button array found in menu JSON","messagePattern":"No button array found in menu JSON","errorType":"exception","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java","lineNumber":106,"sourceCode":"\n  private void addPropertyIfNotNull(JsonObject obj, String key, String value) {\n    if (value != null) {\n      obj.addProperty(key, value);\n    }\n  }\n\n  @Override\n  public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {\n    JsonObject root = json.getAsJsonObject();\n    JsonArray buttonsJson = null;\n    if (root.has(FIELD_MENU)) {\n      JsonObject menuObj = root.getAsJsonObject(FIELD_MENU);\n      buttonsJson = menuObj.getAsJsonArray(FIELD_BUTTON);\n    } else if (root.has(FIELD_BUTTON)) {\n      buttonsJson = root.getAsJsonArray(FIELD_BUTTON);\n    }\n    if (buttonsJson == null) {\n      throw new JsonParseException(\"No button array found in menu JSON\");\n    }\n    return buildMenuFromJson(buttonsJson);\n  }\n\n  protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {\n    WxMenu menu = new WxMenu();\n    for (JsonElement btnElem : buttonsJson) {\n      JsonObject buttonJson = btnElem.getAsJsonObject();\n      WxMenuButton button = convertFromJson(buttonJson);\n      menu.getButtons().add(button);\n      if (buttonJson.has(FIELD_SUB_BUTTON) && buttonJson.get(FIELD_SUB_BUTTON).isJsonArray()) {\n        JsonArray sub_buttonsJson = buttonJson.getAsJsonArray(FIELD_SUB_BUTTON);\n        for (JsonElement subBtnElem : sub_buttonsJson) {\n          button.getSubButtons().add(convertFromJson(subBtnElem.getAsJsonObject()));\n        }\n      }\n    }\n    return menu;","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java#L88-L124","documentation":"Thrown by WxMenuGsonAdapter.deserialize when the menu JSON contains neither a 'menu' object with a 'button' array nor a top-level 'button' array. The adapter looks under FIELD_MENU then FIELD_BUTTON and, finding neither, raises a JsonParseException rather than returning an empty menu.","triggerScenarios":"Deserializing a WeChat menu payload that has an unexpected shape (e.g. an error response, a wrapper with a different key, or a menu query that returned an empty/error object), or passing a hand-built JSON missing the button array.","commonSituations":"Menu get API returned an error object (errcode != 0) that was still fed to the adapter; key renamed in a newer API version; integration test using a stub JSON without a button field.","solutions":["Log the raw JSON being deserialized and confirm it has 'menu.button' or a top-level 'button'.","Check errcode in the response before calling menu deserialization.","Update or wrap the JSON so it carries a button array (possibly empty) if you build it manually."],"exampleFix":"// before\nWxMenu menu = gson.fromJson(rawResponse, WxMenu.class); // rawResponse is an error body\n// after\nJsonObject o = GsonParser.parse(rawResponse);\nif (o.get(WxConsts.ERR_CODE).getAsInt() != 0) {\n  throw new WxErrorException(WxError.fromJson(rawResponse));\n}\nWxMenu menu = gson.fromJson(rawResponse, WxMenu.class);","handlingStrategy":"validation","validationCode":"JsonObject o = GsonParser.parse(rawResponse);\nif (o.get(WxConsts.ERR_CODE) != null && o.get(WxConsts.ERR_CODE).getAsInt() != 0) {\n  throw new WxErrorException(WxError.fromJson(rawResponse, wxType));\n}\nboolean hasButton = (o.has(\"menu\") && o.getAsJsonObject(\"menu\").has(\"button\")) || o.has(\"button\");\nif (!hasButton) throw new IllegalStateException(\"menu payload missing button array\");","typeGuard":"static boolean hasButtonArray(JsonElement e) {\n  JsonObject o = e.getAsJsonObject();\n  return (o.has(\"menu\") && o.getAsJsonObject(\"menu\").has(\"button\")) || o.has(\"button\");\n}","tryCatchPattern":"try {\n  WxMenu m = gson.fromJson(raw, WxMenu.class);\n} catch (JsonParseException e) {\n  log.error(\"menu parse failed; raw={}\", raw);\n  throw e;\n}","preventionTips":["Check errcode before deserializing menu responses.","Log the raw payload to detect schema drift.","Build stub menu JSON with a (possibly empty) button array in tests."],"tags":["gson","json","menu","deserialization"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}