{"record":{"id":"c7d5e90a62dea31c","repo":"material-components/material-components-android","slug":"state-s-should-not-be-set-externally","errorCode":null,"errorMessage":"STATE_%s should not be set externally.","messagePattern":"STATE_(.+?) should not be set externally\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"lib/java/com/google/android/material/sidesheet/SideSheetBehavior.java","lineNumber":635,"sourceCode":"  /**\n   * Removes a previously added callback.\n   *\n   * @param callback The callback to remove.\n   */\n  @Override\n  public void removeCallback(@NonNull SideSheetCallback callback) {\n    callbacks.remove(callback);\n  }\n\n  /**\n   * Sets the state of the sheet. The sheet will transition to that state with animation.\n   *\n   * @param state One of {@link #STATE_EXPANDED} or {@link #STATE_HIDDEN}.\n   */\n  @Override\n  public void setState(@StableSheetState int state) {\n    if (state == STATE_DRAGGING || state == STATE_SETTLING) {\n      throw new IllegalArgumentException(\n          \"STATE_\"\n              + (state == STATE_DRAGGING ? \"DRAGGING\" : \"SETTLING\")\n              + \" should not be set externally.\");\n    }\n    final int finalState = state;\n    if (viewRef == null || viewRef.get() == null) {\n      // The view is not laid out yet; modify state and let onLayoutChild handle it later\n      setStateInternal(state);\n    } else {\n      runAfterLayout(\n          viewRef.get(),\n          () -> {\n            V child = viewRef != null ? viewRef.get() : null;\n            if (child != null) {\n              startSettling(child, finalState, false);\n            }\n          });\n    }","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/material-components/material-components-android/blob/ac7e18efeefb331850c561faf9ab8bf81d27ba68/lib/java/com/google/android/material/sidesheet/SideSheetBehavior.java#L617-L653","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\noverride fun onStateChanged(sheet: View, newState: Int) {\n    behavior.setState(newState) // echoes STATE_DRAGGING/STATE_SETTLING -> crash\n}\n\n// after\noverride fun onStateChanged(sheet: View, newState: Int) {\n    // read-only: update your own UI based on newState; never call setState with it\n}","handlingStrategy":"type-guard","validationCode":"static boolean isUserSettableState(int state) {\n  return state == BottomSheetBehavior.STATE_EXPANDED\n      || state == BottomSheetBehavior.STATE_HIDDEN;\n}\n// usage\nif (isUserSettableState(target)) behavior.setState(target);","typeGuard":"/** Only STATE_EXPANDED and STATE_HIDDEN may be passed to SideSheetBehavior.setState. */\nstatic boolean isStableSheetState(int state) {\n  return state == BottomSheetBehavior.STATE_EXPANDED\n      || state == BottomSheetBehavior.STATE_HIDDEN;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["android","material-components","sidesheet","state-machine","misuse"],"backgroundTag":null,"analyzedSha":"ac7e18efeefb331850c561faf9ab8bf81d27ba68","analyzedAt":"2026-08-14T15:35:35.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}