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

Unexpected labelBehavior:

Error message

Unexpected labelBehavior: 

What it means

IllegalArgumentException thrown in the label-show/hide dispatch switch when labelBehavior is not one of LABEL_GONE, LABEL_FLOATING, or LABEL_WITHIN_BOUNDS. Like the tick mode switch, this default arm is only reachable when a non-IntDef int was forced into setLabelBehavior, and it fires during interaction/layout when labels are added or removed.

Source

Thrown at lib/java/com/google/android/material/slider/BaseSlider.java:3729

        ensureLabelsRemoved();
        break;
      case LABEL_VISIBLE:
        if (isEnabled() && isSliderVisibleOnScreen()) {
          ensureLabelsAdded(/* showLabelOnAllThumbs= */ true);
        } else {
          ensureLabelsRemoved();
        }
        break;
      case LABEL_FLOATING:
      case LABEL_WITHIN_BOUNDS:
        if (activeThumbIdx != -1 && isEnabled()) {
          ensureLabelsAdded(/* showLabelOnAllThumbs= */ false);
        } else {
          ensureLabelsRemoved();
        }
        break;
      default:
        throw new IllegalArgumentException("Unexpected labelBehavior: " + labelBehavior);
    }
  }

  private void updateLabelPivots() {
    // Set the pivot point so that the label pops up in the direction from the thumb.
    final float labelPivotX;
    final float labelPivotY;

    final boolean isVertical = isVertical();
    final boolean isRtl = isRtl();
    if (isVertical && isRtl) {
      labelPivotX = RIGHT_LABEL_PIVOT_X;
      labelPivotY = RIGHT_LABEL_PIVOT_Y;
    } else if (isVertical) {
      labelPivotX = LEFT_LABEL_PIVOT_X;
      labelPivotY = LEFT_LABEL_PIVOT_Y;
    } else {
      labelPivotX = TOP_LABEL_PIVOT_X;

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Only pass Slider.LABEL_* constants to setLabelBehavior.
  2. Validate and sanitize persisted ints against the known set before applying, with a sane default (LABEL_FLOATING).
  3. Store a stable string key instead of the raw ordinal/int value.

Example fix

// before
slider.setLabelBehavior(behaviorFromRemoteConfig); // arbitrary int

// after
int b = behaviorFromRemoteConfig;
slider.setLabelBehavior(
    (b == Slider.LABEL_GONE || b == Slider.LABEL_FLOATING || b == Slider.LABEL_WITHIN_BOUNDS)
        ? b : Slider.LABEL_FLOATING);
Defensive patterns

Strategy: validation

Validate before calling

static boolean isValidLabelBehavior(int b) {
  return b == Slider.LABEL_GONE || b == Slider.LABEL_FLOATING || b == Slider.LABEL_WITHIN_BOUNDS;
}
slider.setLabelBehavior(isValidLabelBehavior(b) ? b : Slider.LABEL_FLOATING);

Prevention

When it happens

Trigger: setLabelBehavior(arbitraryInt) from an untyped source (prefs, Intent extra, remote config), then dragging a thumb or focusing it so ensureLabelsAdded/Removed dispatch runs.

Common situations: Persisting label behavior as a raw int across app/library versions; A/B tests or remote-config flags mapped to ints by hand.

Related errors


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