{"record":{"id":"8dddaa213f893268","repo":"material-components/material-components-android","slug":"materialsplitbutton-can-only-hold-materialbuttons","errorCode":null,"errorMessage":"MaterialSplitButton can only hold MaterialButtons.","messagePattern":"MaterialSplitButton can only hold MaterialButtons\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/button/MaterialSplitButton.java","lineNumber":99,"sourceCode":"  public MaterialSplitButton(@NonNull Context context, @Nullable AttributeSet attrs) {\n    this(context, attrs, R.attr.materialSplitButtonStyle);\n  }\n\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));","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/button/MaterialSplitButton.java#L81-L117","documentation":"MaterialSplitButton is a two-button container (leading action + trailing 'add' chevron) whose implementation depends on every child being a MaterialButton: it casts children to MaterialButton in addView to set checkability, accessibility class name, shape and margins (MaterialSplitButton.java:107). addView therefore throws IllegalArgumentException immediately when any non-MaterialButton view is added, including generic Button subclasses that are not MaterialButtons.","triggerScenarios":"Inflating or programmatically adding a plain Button, ImageButton, TextView or any custom View into a MaterialSplitButton — e.g. <Button> children in XML, or splitButton.addView(new ImageView(context)). Even AppCompatButton is rejected because the instanceof check is against MaterialButton.","commonSituations":"Writing the split button in XML and using the platform <Button> tag out of habit (the same mistake people make inside MaterialButtonToggleGroup). XML inflation calls addView for each child, so the crash occurs at setContentView/inflate time with a stack trace rooted in LayoutInflater.","solutions":["Use fully-qualified <com.google.android.material.button.MaterialButton> elements as the only children of MaterialSplitButton.","If you added views in code, replace addView(new X(...)) with addView(new MaterialButton(context, null, attr)) or inflate a MaterialButton.","Do not put intermediate containers (LinearLayout, Space) inside the split button — it accepts exactly two MaterialButtons, nothing else."],"exampleFix":"<!-- before -->\n<com.google.android.material.button.MaterialSplitButton ...>\n  <Button android:text=\"Save\" ... />\n</com.google.android.material.button.MaterialSplitButton>\n\n<!-- after -->\n<com.google.android.material.button.MaterialSplitButton ...>\n  <com.google.android.material.button.MaterialButton\n      android:text=\"Save\" ... />\n  <com.google.android.material.button.MaterialButton\n      app:icon=\"@drawable/ic_chevron\" ... />\n</com.google.android.material.button.MaterialSplitButton>","handlingStrategy":"type-guard","validationCode":"if (child instanceof MaterialButton) {\n  splitButton.addView(child);\n}","typeGuard":"static boolean isValidSplitChild(View v) {\n  return v instanceof MaterialButton;\n}","tryCatchPattern":"try { splitButton.addView(view); } catch (IllegalArgumentException e) { throw new IllegalStateException(\"MaterialSplitButton children must be MaterialButton\", e); }","preventionTips":["Always use the fully-qualified <com.google.android.material.button.MaterialButton> tag inside the split button.","Never insert plain Button/ImageView/containers as direct children.","Add a custom lint rule banning non-material button tags inside MaterialSplitButton."],"tags":["android","material-components","materialsplitbutton","view-hierarchy","xml-config"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}