material-components/material-components-android · error · IllegalArgumentException
MaterialSplitButton can only hold two MaterialButtons.
Error message
MaterialSplitButton can only hold two MaterialButtons.
What it means
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.
Source
Thrown at lib/java/com/google/android/material/button/MaterialSplitButton.java:102
public MaterialSplitButton(
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);
}
/**
* This override prohibits Views other than {@link MaterialButton} to be added where the leading
* {@link MaterialButton} has either an icon and/or a label and the trailing {@link
* MaterialButton} has an animated vector drawable as an icon. It also makes updates to the add
* button shape and margins.
*/
@Override
public void addView(@NonNull View child, int index, @Nullable ViewGroup.LayoutParams params) {
if (!(child instanceof MaterialButton)) {
throw new IllegalArgumentException("MaterialSplitButton can only hold MaterialButtons.");
}
if (getChildCount() > REQUIRED_BUTTON_COUNT) {
throw new IllegalArgumentException("MaterialSplitButton can only hold two MaterialButtons.");
}
MaterialButton buttonChild = (MaterialButton) child;
super.addView(child, index, params);
if (indexOfChild(child) == 1) {
buttonChild.setCheckable(true);
buttonChild.setA11yClassName(Button.class.getName());
// Set initial content description based on checked state when focused.
ViewCompat.setStateDescription(
buttonChild,
getResources()
.getString(
buttonChild.isChecked()
? R.string.mtrl_button_expanded_content_description
: R.string.mtrl_button_collapsed_content_description));
buttonChild.addOnCheckedChangeListener(
(button, isChecked) -> {View on GitHub (pinned to ac7e18efee)
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.
Example fix
// before splitButton.addView(primary); splitButton.addView(chevron); splitButton.addView(extraAction); // throws // after splitButton.addView(primary); splitButton.addView(chevron); splitButton.getTrailingButton().setOnClickListener(v -> showOverflowMenu(extraActions));
Defensive patterns
Strategy: validation
Validate before calling
if (splitButton.getChildCount() < 2) {
splitButton.addView(new MaterialButton(context));
} Type guard
static boolean canAddToSplitButton(MaterialSplitButton g) {
return g.getChildCount() <= 2;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- MaterialSplitButton can only hold MaterialButtons.
- We already have an EditText, can only have one
- The view is not a child of CoordinatorLayout
- > resourceName < is not a valid ancestor
- > resourceName < is not a valid ancestor
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/58e5ac0ed329db05.
Report an issue: GitHub.