material-components/material-components-android · error · IllegalStateException

Unexpected value: %s

Error message

Unexpected value: %s

What it means

SideSheetBehavior's saved-state offset calculation throws IllegalStateException for a state outside {STATE_EXPANDED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN}. The switch has no default handling for other ints, which almost always means a corrupted or hand-constructed saved-state / unstable state value rather than normal library flow.

Source

Thrown at lib/java/com/google/android/material/sidesheet/SideSheetBehavior.java:469

    return innerMargin;
  }

  private int calculateCurrentOffset(int savedOuterEdge, V child) {
    int currentOffset;

    switch (state) {
      case STATE_EXPANDED:
        currentOffset = 0;
        break;
      case STATE_DRAGGING:
      case STATE_SETTLING:
        currentOffset = savedOuterEdge - sheetDelegate.getOuterEdge(child);
        break;
      case STATE_HIDDEN:
        currentOffset = sheetDelegate.getHiddenOffset();
        break;
      default:
        throw new IllegalStateException("Unexpected value: " + state);
    }
    return currentOffset;
  }

  @Override
  public boolean onInterceptTouchEvent(
      @NonNull CoordinatorLayout parent, @NonNull V child, @NonNull MotionEvent event) {
    if (!shouldInterceptTouchEvent(child)) {
      ignoreEvents = true;
      return false;
    }
    int action = event.getActionMasked();
    // Record the velocity
    if (action == MotionEvent.ACTION_DOWN) {
      resetVelocity();
    }
    if (velocityTracker == null) {
      velocityTracker = VelocityTracker.obtain();

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Only ever set states via setState(STATE_EXPANDED / STATE_HIDDEN) and let the library persist its own SavedState.
  2. If you persist state yourself, store only stable states and rehydrate by calling setState() with a valid constant.
  3. For tests, use the library's constants instead of raw ints.

Example fix

// before
outState.putInt("sheet_state", currentCustomStateInt); // may hold invalid value
...
behavior.setState(restoredInt);

// after
outState.putBoolean("sheet_expanded", behavior.getState() == BottomSheetBehavior.STATE_EXPANDED);
...
behavior.setState(restoredExpanded ? BottomSheetBehavior.STATE_EXPANDED
                                   : BottomSheetBehavior.STATE_HIDDEN);
Defensive patterns

Strategy: validation

Validate before calling

static boolean isKnownSheetState(int state) {
  return state == BottomSheetBehavior.STATE_EXPANDED
      || state == BottomSheetBehavior.STATE_DRAGGING
      || state == BottomSheetBehavior.STATE_SETTLING
      || state == BottomSheetBehavior.STATE_HIDDEN;
}

Prevention

When it happens

Trigger: Restoring a SideSheetBehavior.SavedState written with parceling bugs, or calling internal state APIs with an arbitrary int; also reachable from code that writes STATE_DRAGGING-like custom constants into the behavior's state.

Common situations: Custom Parcelable for a screen that manually serializes sheet state and deserializes an invalid int; process-death restore where a stale version of the saved state format is read; reflective or state-injection tricks used in tests.

Related errors


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