material-components/material-components-android · error · IllegalArgumentException
iconGravity cannot have the same alignment as…
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.
Solutions
- Give the two gravities different alignments, e.g. iconGravity="start" with secondaryIconGravity="end" (the typical icon + chevron pattern).
- If only one icon is needed, remove the secondary icon (unset app:secondaryIcon / secondaryIcon null) so validation passes regardless of gravity values.
- 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
- Use distinct alignments (e.g. primary=start, secondary=end) in shared styles.
- Only set a secondary icon when the gravity attributes are guaranteed different.
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
- iconSize cannot be less than 0
- AppBarLayout is always vertical and does not support…
- Invalid view edge position value:
- Album does not exist.
- Animator must be an ObjectAnimator:
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/bcc4466155a63fcb.
Report an issue: GitHub.
Appendix: 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: // endView on GitHub (pinned to ac7e18efee)