{"record":{"id":"58e5ac0ed329db05","repo":"material-components/material-components-android","slug":"materialsplitbutton-can-only-hold-two-materialbutt","errorCode":null,"errorMessage":"MaterialSplitButton can only hold two MaterialButtons.","messagePattern":"MaterialSplitButton can only hold two MaterialButtons\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/button/MaterialSplitButton.java","lineNumber":102,"sourceCode":"\n  public MaterialSplitButton(\n      @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n    super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);\n  }\n\n  /**\n   * This override prohibits Views other than {@link MaterialButton} to be added where the leading\n   * {@link MaterialButton} has either an icon and/or a label and the trailing {@link\n   * MaterialButton} has an animated vector drawable as an icon. It also makes updates to the add\n   * button shape and margins.\n   */\n  @Override\n  public void addView(@NonNull View child, int index, @Nullable ViewGroup.LayoutParams params) {\n    if (!(child instanceof MaterialButton)) {\n      throw new IllegalArgumentException(\"MaterialSplitButton can only hold MaterialButtons.\");\n    }\n    if (getChildCount() > REQUIRED_BUTTON_COUNT) {\n      throw new IllegalArgumentException(\"MaterialSplitButton can only hold two MaterialButtons.\");\n    }\n\n    MaterialButton buttonChild = (MaterialButton) child;\n    super.addView(child, index, params);\n    if (indexOfChild(child) == 1) {\n      buttonChild.setCheckable(true);\n      buttonChild.setA11yClassName(Button.class.getName());\n      // Set initial content description based on checked state when focused.\n      ViewCompat.setStateDescription(\n          buttonChild,\n          getResources()\n              .getString(\n                  buttonChild.isChecked()\n                      ? R.string.mtrl_button_expanded_content_description\n                      : R.string.mtrl_button_collapsed_content_description));\n\n      buttonChild.addOnCheckedChangeListener(\n          (button, isChecked) -> {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/button/MaterialSplitButton.java#L84-L120","documentation":"MaterialSplitButton models exactly one action plus one trailing chevron button: REQUIRED_BUTTON_COUNT is 2 (MaterialSplitButton.java:75), and addView throws IllegalArgumentException when getChildCount() is already > 2, i.e. when a third child is being added. The container's checked-state handling, shape stitching and accessibility logic all assume the two-button structure, so extra children are rejected outright.","triggerScenarios":"Declaring three or more children in the MaterialSplitButton's XML (inflation calls addView per child, so the third child trips the check), or calling addView more than twice programmatically. Note the guard uses getChildCount() > REQUIRED_BUTTON_COUNT, so the throw fires on the attempt to add a fourth slot's worth of existing children — any child beyond the intended two-part structure is invalid.","commonSituations":"Trying to build a multi-action split (e.g. 'Save | Save As | Export') by adding a third MaterialButton — developers expect a menu-like container but the component only supports the leading action plus the built-in trailing chevron that opens a menu you provide separately. Dynamic content that inserts status TextViews or badges into the split button also triggers it.","solutions":["Keep exactly two MaterialButton children: the main action and the trailing chevron button; put extra actions in the popup menu shown when the chevron is pressed.","Remove extra children (badges, spacers, labels) from the XML and attach them outside the split button or via the button's icon/text APIs.","If you truly need N visible segments, use MaterialButtonToggleGroup or MaterialButtonGroup instead."],"exampleFix":"// before\nsplitButton.addView(primary);\nsplitButton.addView(chevron);\nsplitButton.addView(extraAction); // throws\n\n// after\nsplitButton.addView(primary);\nsplitButton.addView(chevron);\nsplitButton.getTrailingButton().setOnClickListener(v -> showOverflowMenu(extraActions));","handlingStrategy":"validation","validationCode":"if (splitButton.getChildCount() < 2) {\n  splitButton.addView(new MaterialButton(context));\n}","typeGuard":"static boolean canAddToSplitButton(MaterialSplitButton g) {\n  return g.getChildCount() <= 2;\n}","tryCatchPattern":null,"preventionTips":["Design split buttons as exactly two MaterialButtons; extra actions go in the chevron's popup menu.","Attach badges/labels outside the container or via icon APIs.","Use MaterialButtonToggleGroup for N-segment UIs."],"tags":["android","material-components","materialsplitbutton","view-hierarchy"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}