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

Invalid state to get outer edge offset: %d

Error message

Invalid state to get outer edge offset: %d

What it means

SideSheetBehavior.getOuterEdgeOffsetForState() throws IllegalArgumentException for any state other than STATE_EXPANDED and STATE_HIDDEN. It maps a stable target state to the pixel offset the sheet should settle to; transient states (DRAGGING/SETTLING) and any other int have no target offset, hence the rejection.

Source

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

   * {@link StateSettlingTracker}.
   */
  private boolean isSettling(View child, int state, boolean isReleasingView) {
    int left = getOuterEdgeOffsetForState(state);
    ViewDragHelper viewDragHelper = getViewDragHelper();
    return viewDragHelper != null
        && (isReleasingView
            ? viewDragHelper.settleCapturedViewAt(left, child.getTop())
            : viewDragHelper.smoothSlideViewTo(child, left, child.getTop()));
  }

  int getOuterEdgeOffsetForState(@StableSheetState int state) {
    switch (state) {
      case STATE_EXPANDED:
        return getExpandedOffset();
      case STATE_HIDDEN:
        return sheetDelegate.getHiddenOffset();
      default:
        throw new IllegalArgumentException("Invalid state to get outer edge offset: " + state);
    }
  }

  @Nullable
  ViewDragHelper getViewDragHelper() {
    return viewDragHelper;
  }

  private final ViewDragHelper.Callback dragCallback =
      new ViewDragHelper.Callback() {

        @Override
        public boolean tryCaptureView(@NonNull View child, int pointerId) {
          if (state == STATE_DRAGGING) {
            return false;
          }
          return viewRef != null && viewRef.get() == child;
        }

View on GitHub (pinned to ac7e18efee)

Solutions

  1. Restrict state arguments to BottomSheetBehavior.STATE_EXPANDED and STATE_HIDDEN when driving side sheets.
  2. Validate any restored/persisted state before calling state APIs: map unknown values to a safe default.
  3. Do not port BottomSheetDialog state constants (e.g. half-expanded) to SideSheetBehavior.

Example fix

// before
behavior.setState(savedState); // savedState could be STATE_DRAGGING/SETTLING/other

// after
int safe = (savedState == BottomSheetBehavior.STATE_HIDDEN)
        ? BottomSheetBehavior.STATE_HIDDEN
        : BottomSheetBehavior.STATE_EXPANDED;
behavior.setState(safe);
Defensive patterns

Strategy: type-guard

Validate before calling

static int safeSheetState(int state) {
  return state == BottomSheetBehavior.STATE_HIDDEN
      ? BottomSheetBehavior.STATE_HIDDEN
      : BottomSheetBehavior.STATE_EXPANDED;
}

Type guard

/** SideSheet state APIs accept only EXPANDED and HIDDEN. */
static boolean isSideSheetTargetState(int state) {
  return state == BottomSheetBehavior.STATE_EXPANDED
      || state == BottomSheetBehavior.STATE_HIDDEN;
}

Prevention

When it happens

Trigger: Calling this package-visible method (or a code path that uses it, like setState on an unlaid-out view with an invalid state) with e.g. STATE_DRAGGING, STATE_SETTLING, STATE_HALF_EXPANDED, or a custom int.

Common situations: Reusing a state int from BottomSheetBehavior code that includes half-expanded semantics; passing a state restored from a bundle without validation; test code poking internal offsets with arbitrary states.

Related errors


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