binarywang/WxJava · error · JsonParseException

No button array found in menu JSON

Error message

No button array found in menu JSON

What it means

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.

Source

Thrown at weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java:106

  private void addPropertyIfNotNull(JsonObject obj, String key, String value) {
    if (value != null) {
      obj.addProperty(key, value);
    }
  }

  @Override
  public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    JsonObject root = json.getAsJsonObject();
    JsonArray buttonsJson = null;
    if (root.has(FIELD_MENU)) {
      JsonObject menuObj = root.getAsJsonObject(FIELD_MENU);
      buttonsJson = menuObj.getAsJsonArray(FIELD_BUTTON);
    } else if (root.has(FIELD_BUTTON)) {
      buttonsJson = root.getAsJsonArray(FIELD_BUTTON);
    }
    if (buttonsJson == null) {
      throw new JsonParseException("No button array found in menu JSON");
    }
    return buildMenuFromJson(buttonsJson);
  }

  protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
    WxMenu menu = new WxMenu();
    for (JsonElement btnElem : buttonsJson) {
      JsonObject buttonJson = btnElem.getAsJsonObject();
      WxMenuButton button = convertFromJson(buttonJson);
      menu.getButtons().add(button);
      if (buttonJson.has(FIELD_SUB_BUTTON) && buttonJson.get(FIELD_SUB_BUTTON).isJsonArray()) {
        JsonArray sub_buttonsJson = buttonJson.getAsJsonArray(FIELD_SUB_BUTTON);
        for (JsonElement subBtnElem : sub_buttonsJson) {
          button.getSubButtons().add(convertFromJson(subBtnElem.getAsJsonObject()));
        }
      }
    }
    return menu;

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Log the raw JSON being deserialized and confirm it has 'menu.button' or a top-level 'button'.
  2. Check errcode in the response before calling menu deserialization.
  3. Update or wrap the JSON so it carries a button array (possibly empty) if you build it manually.

Example fix

// before
WxMenu menu = gson.fromJson(rawResponse, WxMenu.class); // rawResponse is an error body
// after
JsonObject o = GsonParser.parse(rawResponse);
if (o.get(WxConsts.ERR_CODE).getAsInt() != 0) {
  throw new WxErrorException(WxError.fromJson(rawResponse));
}
WxMenu menu = gson.fromJson(rawResponse, WxMenu.class);
Defensive patterns

Strategy: validation

Validate before calling

JsonObject o = GsonParser.parse(rawResponse);
if (o.get(WxConsts.ERR_CODE) != null && o.get(WxConsts.ERR_CODE).getAsInt() != 0) {
  throw new WxErrorException(WxError.fromJson(rawResponse, wxType));
}
boolean hasButton = (o.has("menu") && o.getAsJsonObject("menu").has("button")) || o.has("button");
if (!hasButton) throw new IllegalStateException("menu payload missing button array");

Type guard

static boolean hasButtonArray(JsonElement e) {
  JsonObject o = e.getAsJsonObject();
  return (o.has("menu") && o.getAsJsonObject("menu").has("button")) || o.has("button");
}

Try / catch

try {
  WxMenu m = gson.fromJson(raw, WxMenu.class);
} catch (JsonParseException e) {
  log.error("menu parse failed; raw={}", raw);
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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