material-components/material-components-android · error · IllegalArgumentException

iconGravity cannot have the same alignment as secondaryIconG

Error message

iconGravity cannot have the same alignment as secondaryIconGravity

What it means

MaterialButton supports an optional secondary icon (e.g. for dropdown/chevron usage). The primary iconGravity and secondaryIconGravity must not resolve to the same alignment (start/end/top) when both icons are set, otherwise the two drawables would be stacked in the same compound-drawable slot. validateIconGravity enforces this with IllegalArgumentException whenever both icons exist and areIconsGravitySameAlignment() is true.

Source

Thrown at lib/java/com/google/android/material/button/MaterialButton.java:1258

    boolean hasIconChanged =
        (isIconStart() && drawableStart != icon)
            || (isIconEnd() && drawableEnd != icon)
            || (isIconTop() && drawableTop != icon);
    // Force icon update if needsIconReset otherwise updated it only if icon has changed.
    if (needsIconReset || hasIconChanged) {
      if (isIconStart()) {
        setCompoundDrawablesRelative(icon, getUpdatedIconFor(1), getUpdatedIconFor(2), null);
      } else if (isIconEnd()) {
        setCompoundDrawablesRelative(getUpdatedIconFor(0), getUpdatedIconFor(1), icon, null);
      } else if (isIconTop()) {
        setCompoundDrawablesRelative(getUpdatedIconFor(0), icon, getUpdatedIconFor(2), null);
      }
    }
  }

  private void validateIconGravity() {
    if (icon != null && secondaryIcon != null && areIconsGravitySameAlignment()) {
      throw new IllegalArgumentException(
          "iconGravity cannot have the same alignment as secondaryIconGravity");
    }
  }

  private boolean areIconsGravitySameAlignment() {
    return (isIconStart() && isSecondaryIconStart())
        || (isIconEnd() && isSecondaryIconEnd())
        || (isIconTop() && isSecondaryIconTop());
  }

  @Nullable
  private Drawable getUpdatedIconFor(int position) {
    switch (position) {
      case 0: // start
        return (secondaryIcon != null && isSecondaryIconStart()) ? secondaryIcon : null;
      case 1: // top
        return (secondaryIcon != null && isSecondaryIconTop()) ? secondaryIcon : null;
      case 2: // end

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Give the two gravities different alignments, e.g. iconGravity="start" with secondaryIconGravity="end" (the typical icon + chevron pattern).
  2. If only one icon is needed, remove the secondary icon (unset app:secondaryIcon / secondaryIcon null) so validation passes regardless of gravity values.
  3. When setting gravities programmatically, keep a mapping/constant pair that is guaranteed distinct.

Example fix

<!-- before -->
<com.google.android.material.button.MaterialButton
    app:icon="@drawable/ic_send"
    app:iconGravity="start"
    app:secondaryIcon="@drawable/ic_chevron_down"
    app:secondaryIconGravity="start" ... /> <!-- throws -->

<!-- after -->
<com.google.android.material.button.MaterialButton
    app:icon="@drawable/ic_send"
    app:iconGravity="start"
    app:secondaryIcon="@drawable/ic_chevron_down"
    app:secondaryIconGravity="end" ... />
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the gravities differ whenever both icons are present
if (icon != null && secondaryIcon != null) {
  android.util.Log.d(TAG, "primary=" + iconGravity + " secondary=" + secondaryIconGravity);
  // require: not (start&start), (end&end), or (top&top)
}

Type guard

private static boolean gravitiesConflict(int primaryGravity, int secondaryGravity) {
  return primaryGravity == secondaryGravity; // same start/end/top alignment
}
// usage: if (!gravitiesConflict(iconGravity, secondaryIconGravity)) button.setSecondaryIcon(chevron);

Prevention

When it happens

Trigger: Setting both icon and secondaryIcon on the same MaterialButton with app:iconGravity and app:secondaryIconGravity both resolving to start, end, or top; changing gravity attributes in XML or calling the gravity setters so both align identically.

Common situations: Adding a secondary icon (e.g. a chevron) to an existing button that already has iconGravity="start" and copying the same value for secondaryIconGravity; configuring gravity from a shared style/theme so both attributes inherit the same alignment; programmatically toggling gravities at runtime without keeping them distinct.

Related errors


AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14). Data as JSON: /api/errors/bcc4466155a63fcb. Report an issue: GitHub.