Skip to content

[JEWEL-1075] Fix crash in ScrollableContainer when used with IntrinsicSize#3471

Open
DanielSouzaBertoldi wants to merge 1 commit intoJetBrains:masterfrom
DanielSouzaBertoldi:dsb/JEWEL-1075
Open

[JEWEL-1075] Fix crash in ScrollableContainer when used with IntrinsicSize#3471
DanielSouzaBertoldi wants to merge 1 commit intoJetBrains:masterfrom
DanielSouzaBertoldi:dsb/JEWEL-1075

Conversation

@DanielSouzaBertoldi
Copy link
Copy Markdown
Collaborator

@DanielSouzaBertoldi DanielSouzaBertoldi commented Mar 25, 2026

(this description was generated by jewel-pr-preparer)

Context

VerticallyScrollableContainer (and its horizontal counterpart) crashed with IllegalArgumentException when being used inside a Composable that expects IntrincisSize. This is the crash stacktrace:

Caused by: java.lang.IllegalArgumentException: Can't represent a width of 0 and height of 2147483647 in Constraints
	at androidx.compose.ui.unit.ConstraintsKt.throwInvalidConstraintException(Constraints.kt:401)
	at androidx.compose.ui.unit.ConstraintsKt.createConstraints(Constraints.kt:425)
	at androidx.compose.ui.unit.Constraints$Companion.fixedHeight-OenEA2s(Constraints.kt:244)
	at org.jetbrains.jewel.ui.component.ScrollableContainerKt$ScrollableContainerImpl$2$1.measure-3p2s80s(ScrollableContainer.kt:779)
	at androidx.compose.ui.layout.MeasurePolicy.maxIntrinsicHeight(MeasurePolicy.kt:164)
	at androidx.compose.ui.node.IntrinsicsPolicy.maxIntrinsicHeight(IntrinsicsPolicy.kt:53)
	at androidx.compose.ui.node.LayoutNode.maxIntrinsicHeight(LayoutNode.kt:764)
	at androidx.compose.ui.node.InnerNodeCoordinator.maxIntrinsicHeight(InnerNodeCoordinator.kt:140)

Compose's default MeasurePolicy intrinsic fallback re-runs the measure block with Constraints.Infinity on the queried axis. The old implementation used a SAM lambda for Layout { }, so the measure block would run during intrinsic queries. Inside that block, the scrollbar was being measured with Constraints.fixedHeight(Int.MAX_VALUE), an illegal Constraints value that throws immediately.

Changes

  • Changed the measurement order in ScrollableContainer: instead of measuring scrollbars with Constraints.fixedHeight/Width(Int.MAX_VALUE) to query their size, the implementation now queries scrollbar intrinsic sizes first by converting the Layout SAM lambda to an explicit MeasurePolicy object with proper intrinsic overrides, then measures content, then measures scrollbars with concrete dimensions.
  • This alone was not enough; the scrollbar Layout lambdas in Scrollbar.kt were themselves using SAM lambdas with no intrinsic overrides as well, so Compose's default fallback would re-run their measure blocks with
    Constraints.Infinity, causing the same crash one level deeper. Both verticalMeasurePolicy and horizontalMeasurePolicy were converted to explicit MeasurePolicy objects that report thumbThickness as the intrinsic size on their fixed axis and 0 on the scroll axis.
  • Added check() assertions (matching LazyColumn's behavior) that throw IllegalStateException with a descriptive message when the scroll axis has an unbounded constraint during actual layout, giving developers clear guidance instead of a cryptic crash deep in Compose internals.
  • Added comprehensive tests to ScrollableContainerTest covering: no crash in IntrinsicSize.Max/IntrinsicSize.Min parents, correct reported intrinsic dimensions (including scrollbar space for the macOS AlwaysVisible style), scrolling still works after the fix, and unbounded-axis nesting produces the expected IllegalStateException.

Release notes

Bug fixes

  • VerticallyScrollableContainer and HorizontallyScrollableContainer no longer crash with IllegalArgumentException when placed inside a layout that queries intrinsic measurements.

…cSize

When a VerticallyScrollableContainer or HorizontallyScrollableContainer
was placed inside a layout querying intrinsic measurements (e.g.,
Column(Modifier.width(IntrinsicSize.Max))), Compose's default MeasurePolicy
fallback re-ran the measure block with Constraints.Infinity. The scrollbar
measurement then called Constraints.fixedHeight(Int.MAX_VALUE), which is
an illegal Constraints value and threw an IllegalArgumentException.

Fix the crash by converting the Layout SAM lambdas in ScrollableContainer
and the scrollbar measure policies in Scrollbar to explicit MeasurePolicy
objects with proper intrinsic overrides. The scrollbar policies report their
thumb thickness as intrinsic width/height on the fixed axis and 0 on the
scroll axis. ScrollableContainer queries scrollbar intrinsic sizes first,
then measures content and scrollbars with concrete constraints, avoiding any
unbounded intermediate measurement.

Additionally add LazyColumn-style check() assertions that throw
IllegalStateException when the scroll axis has an unbounded constraint
during actual layout, giving developers a clear error message instead of a
cryptic crash deep in Constraints internals.

Tests covering all edge cases are added to ScrollableContainerTest:
intrinsic-size parents no longer crash, containers report correct intrinsic
widths (including scrollbar space on macOS AlwaysVisible), scrolling still
works after the fix, and unbounded-axis nesting produces the expected
IllegalStateException with a descriptive message.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant