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

Invalid fit mode: > fitMode <

Error message

Invalid fit mode: > fitMode <

What it means

FitModeEvaluators.get (FitModeEvaluators.java:132) chooses whether a MaterialContainerTransform fits the incoming/outgoing content to width or height. Only FIT_MODE_AUTO, FIT_MODE_WIDTH and FIT_MODE_HEIGHT are accepted; anything else reaches the default branch and throws IllegalArgumentException. The value comes from MaterialContainerTransform.setFitMode().

Source

Thrown at lib/java/com/google/android/material/transition/FitModeEvaluators.java:132

        public void applyMask(RectF maskBounds, float maskMultiplier, FitModeResult fitModeResult) {
          float currentWidthDiff =
              Math.abs(fitModeResult.currentEndWidth - fitModeResult.currentStartWidth);
          maskBounds.left += currentWidthDiff / 2 * maskMultiplier;
          maskBounds.right -= currentWidthDiff / 2 * maskMultiplier;
        }
      };

  static FitModeEvaluator get(
      @FitMode int fitMode, boolean entering, RectF startBounds, RectF endBounds) {
    switch (fitMode) {
      case FIT_MODE_AUTO:
        return shouldAutoFitToWidth(entering, startBounds, endBounds) ? WIDTH : HEIGHT;
      case FIT_MODE_WIDTH:
        return WIDTH;
      case FIT_MODE_HEIGHT:
        return HEIGHT;
      default:
        throw new IllegalArgumentException("Invalid fit mode: " + fitMode);
    }
  }

  private static boolean shouldAutoFitToWidth(
      boolean entering, RectF startBounds, RectF endBounds) {
    float startWidth = startBounds.width();
    float startHeight = startBounds.height();
    float endWidth = endBounds.width();
    float endHeight = endBounds.height();

    float endHeightFitToWidth = endHeight * startWidth / endWidth;
    float startHeightFitToWidth = startHeight * endWidth / startWidth;
    return entering ? endHeightFitToWidth >= startHeight : startHeightFitToWidth >= endHeight;
  }

  private FitModeEvaluators() {}
}

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Use MaterialContainerTransform.FIT_MODE_AUTO / FIT_MODE_WIDTH / FIT_MODE_HEIGHT.
  2. Whitelist-check any dynamic value before setFitMode().
  3. Annotate your wrapper's parameter with @FitMode so the IDE/lint flags invalid constants.

Example fix

// before
transform.setFitMode(9);

// after
transform.setFitMode(MaterialContainerTransform.FIT_MODE_WIDTH);
Defensive patterns

Strategy: validation

Validate before calling

static @FitMode int coerceFitMode(int candidate) {
  if (candidate == MaterialContainerTransform.FIT_MODE_WIDTH
      || candidate == MaterialContainerTransform.FIT_MODE_HEIGHT) return candidate;
  return MaterialContainerTransform.FIT_MODE_AUTO;
}
transform.setFitMode(coerceFitMode(rawFitMode));

Type guard

static boolean isValidFitMode(int m) {
  return m == MaterialContainerTransform.FIT_MODE_AUTO
      || m == MaterialContainerTransform.FIT_MODE_WIDTH
      || m == MaterialContainerTransform.FIT_MODE_HEIGHT;
}

Prevention

When it happens

Trigger: Calling transform.setFitMode(x) with an int outside the FIT_MODE_* constant set; passing a value round-tripped through saved state or serialization without validation; mixing up constants from a different class (e.g. a fade mode constant).

Common situations: Numeric hardcoding instead of constants; copy-paste between setFadeMode and setFitMode calls; remote-config-driven transition tuning with unchecked ints.

Related errors


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