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

Invalid transition direction: > transitionDirection <

Error message

Invalid transition direction: > transitionDirection <

What it means

MaterialContainerTransform.isEntering (MaterialContainerTransform.java:1041) interprets the configured transition direction to decide whether the animation plays as enter or return. TRANSITION_DIRECTION_AUTO compares start/end areas, ENTER and RETURN force the direction; any other int throws IllegalArgumentException. The value originates from setTransitionDirection().

Source

Thrown at lib/java/com/google/android/material/transition/MaterialContainerTransform.java:1041

    if (boundingView != null) {
      RectF drawableBounds = getLocationInWindow(boundingView);
      drawableBounds.offset(offsetX, offsetY);
      return drawableBounds;
    } else {
      return new RectF(0, 0, drawingView.getWidth(), drawingView.getHeight());
    }
  }

  private boolean isEntering(@NonNull RectF startBounds, @NonNull RectF endBounds) {
    switch (transitionDirection) {
      case TRANSITION_DIRECTION_AUTO:
        return calculateArea(endBounds) > calculateArea(startBounds);
      case TRANSITION_DIRECTION_ENTER:
        return true;
      case TRANSITION_DIRECTION_RETURN:
        return false;
      default:
        throw new IllegalArgumentException("Invalid transition direction: " + transitionDirection);
    }
  }

  private ProgressThresholdsGroup buildThresholdsGroup(boolean entering) {
    PathMotion pathMotion = getPathMotion();
    if (pathMotion instanceof ArcMotion || pathMotion instanceof MaterialArcMotion) {
      return getThresholdsOrDefault(
          entering, DEFAULT_ENTER_THRESHOLDS_ARC, DEFAULT_RETURN_THRESHOLDS_ARC);
    } else {
      return getThresholdsOrDefault(entering, DEFAULT_ENTER_THRESHOLDS, DEFAULT_RETURN_THRESHOLDS);
    }
  }

  private ProgressThresholdsGroup getThresholdsOrDefault(
      boolean entering,
      ProgressThresholdsGroup defaultEnterThresholds,
      ProgressThresholdsGroup defaultReturnThresholds) {
    ProgressThresholdsGroup defaultThresholds =

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Use MaterialContainerTransform.TRANSITION_DIRECTION_AUTO / TRANSITION_DIRECTION_ENTER / TRANSITION_DIRECTION_RETURN.
  2. Validate persisted/dynamic values: if not one of the three constants, fall back to TRANSITION_DIRECTION_AUTO.
  3. Annotate wrapper APIs with @TransitionDirection to get compile-time constant checking.

Example fix

// before
transform.setTransitionDirection(5);

// after
transform.setTransitionDirection(MaterialContainerTransform.TRANSITION_DIRECTION_ENTER);
Defensive patterns

Strategy: validation

Validate before calling

static @TransitionDirection int coerceDirection(int d) {
  return (d == MaterialContainerTransform.TRANSITION_DIRECTION_AUTO
       || d == MaterialContainerTransform.TRANSITION_DIRECTION_ENTER
       || d == MaterialContainerTransform.TRANSITION_DIRECTION_RETURN)
      ? d : MaterialContainerTransform.TRANSITION_DIRECTION_AUTO;
}
transform.setTransitionDirection(coerceDirection(savedDir));

Type guard

static boolean isValidTransitionDirection(int d) {
  return d >= MaterialContainerTransform.TRANSITION_DIRECTION_AUTO
      && d <= MaterialContainerTransform.TRANSITION_DIRECTION_RETURN;
}

Prevention

When it happens

Trigger: Calling transform.setTransitionDirection(v) with a value other than TRANSITION_DIRECTION_AUTO/ENTER/RETURN and starting the transition; restoring a direction from persistence with a stale or invalid number.

Common situations: Hardcoded numeric direction; constants confused with fade/fit mode ints; version migration where saved ints no longer map to valid constants.

Related errors


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