material-components/material-components-android · error · IllegalArgumentException
STATE_%s should not be set externally.
Error message
STATE_%s should not be set externally.
What it means
SideSheetBehavior.setState() throws IllegalArgumentException when passed STATE_DRAGGING or STATE_SETTLING. Those two states are transient: they only have meaning while the user is dragging or the sheet is mid-settle, driven internally by ViewDragHelper; externally setting them would corrupt the state machine. The public API accepts only STATE_EXPANDED and STATE_HIDDEN.
Source
Thrown at lib/java/com/google/android/material/sidesheet/SideSheetBehavior.java:635
/**
* Removes a previously added callback.
*
* @param callback The callback to remove.
*/
@Override
public void removeCallback(@NonNull SideSheetCallback callback) {
callbacks.remove(callback);
}
/**
* Sets the state of the sheet. The sheet will transition to that state with animation.
*
* @param state One of {@link #STATE_EXPANDED} or {@link #STATE_HIDDEN}.
*/
@Override
public void setState(@StableSheetState int state) {
if (state == STATE_DRAGGING || state == STATE_SETTLING) {
throw new IllegalArgumentException(
"STATE_"
+ (state == STATE_DRAGGING ? "DRAGGING" : "SETTLING")
+ " should not be set externally.");
}
final int finalState = state;
if (viewRef == null || viewRef.get() == null) {
// The view is not laid out yet; modify state and let onLayoutChild handle it later
setStateInternal(state);
} else {
runAfterLayout(
viewRef.get(),
() -> {
V child = viewRef != null ? viewRef.get() : null;
if (child != null) {
startSettling(child, finalState, false);
}
});
}View on GitHub (pinned to ac7e18efee)
Solutions
- Only call setState() with STATE_EXPANDED or STATE_HIDDEN.
- In onStateChanged callbacks, never feed the received state back into setState(); treat transient states as read-only signals.
- Delete or guard any generic setState(state) forwarding path with a whitelist check.
Example fix
// before
override fun onStateChanged(sheet: View, newState: Int) {
behavior.setState(newState) // echoes STATE_DRAGGING/STATE_SETTLING -> crash
}
// after
override fun onStateChanged(sheet: View, newState: Int) {
// read-only: update your own UI based on newState; never call setState with it
} Defensive patterns
Strategy: type-guard
Validate before calling
static boolean isUserSettableState(int state) {
return state == BottomSheetBehavior.STATE_EXPANDED
|| state == BottomSheetBehavior.STATE_HIDDEN;
}
// usage
if (isUserSettableState(target)) behavior.setState(target); Type guard
/** Only STATE_EXPANDED and STATE_HIDDEN may be passed to SideSheetBehavior.setState. */
static boolean isStableSheetState(int state) {
return state == BottomSheetBehavior.STATE_EXPANDED
|| state == BottomSheetBehavior.STATE_HIDDEN;
} Prevention
- Never echo onStateChanged values back into setState().
- Treat DRAGGING/SETTLING as read-only progress signals for UI only.
- Whitelist states at every setState call site.
When it happens
Trigger: Calling sideSheetBehavior.setState(BottomSheetBehavior.STATE_DRAGGING) or STATE_SETTLING from app code — often by forwarding a state observed from a callback (e.g. onStateChanged reporting STATE_SETTLING is written back via setState).
Common situations: Echoing callback states back ('state restoration' code that does setState(newState) inside onStateChanged); copy-paste from BottomSheet examples that enumerate all 5 states; switch UIs mapping all states to buttons.
Related errors
- Invalid state to get outer edge offset: %d
- Sheet view reference is null; sheet edge cannot be changed i
- Sheet view has been laid out; sheet edge cannot be changed o
- Invalid sheet edge position value: %d. Must be %d or %d.
- Unexpected value: %s
AI-assisted analysis of material-components/material-components-android@ac7e18efee (2026-08-14).
Data as JSON: /api/errors/c7d5e90a62dea31c.
Report an issue: GitHub.