
Flutter: The 'Vertical viewport was given unbounded height' Error
Why does putting a ListView inside a Column cause a white screen or crash? Understand the 'Unbounded Height' paradox and solve it elegantly with Expanded and Slivers.

Why does putting a ListView inside a Column cause a white screen or crash? Understand the 'Unbounded Height' paradox and solve it elegantly with Expanded and Slivers.
Yellow stripes appear when the keyboard pops up? Learn how to handle layout overflows using resizeToAvoidBottomInset, SingleChildScrollView, and tricks for chat apps.

Push works on Android but silent on iOS? Learn to fix APNs certificates, handle background messages, configure Notification Channels, and debug FCM integration errors.

Think Android is easier than iOS? Meet Gradle Hell. Learn to fix minSdkVersion conflicts, Multidex limit errors, Namespace issues in Gradle 8.0, and master dependency analysis with `./gradlew dependencies`.

App crashes only in Release mode? It's likely ProGuard/R8. Learn how to debug obfuscated stack traces, use `@Keep` annotations, and analyze `usage.txt`.

The #2 scariest moment for a Flutter dev (after build errors) is launching the app to see a White Screen of Death, or a red screen yelling "Vertical viewport was given unbounded height."
The code was simple:
Column(
children: [
Text("My Todo List"), // Header
ListView.builder( // List
itemCount: 100,
itemBuilder: (context, index) => Text("Task $index"),
),
],
)
"Wait, putting a list under a title is hard?" Yes, in Flutter's layout universe, this is a deep philosophical paradox.
The core of this error is a fight over "Who decides the Height?"
Column arranges children vertically. It asks children: "How much height do you need? I'll give it to you." (Respects children's size).ListView is scrollable. This implies content is longer than the screen. Theoretically, ListView has Infinite Height.Column: "Hey ListView, what's your height? I need to draw you."ListView: "I am Infinite."Column: "..." (Cannot draw infinity).Unbounded height error. Flutter cannot render a widget with infinite height inside a layout that tries to wrap content.Tell ListView: "Stop claiming infinity. Just take whatever space Column has left."
Column(
children: [
Text("My Todo List"), // Fixed size (e.g., 50px)
Expanded( // Takes ALL remaining space
child: ListView.builder(
itemCount: 100,
itemBuilder: ...,
),
),
],
)
Expanded calculates the remaining height of the screen (Total - 50px) and forces a Bounded Height onto ListView.
ListView realizes, "Oh, I only exist within this box," and creates a scroll view normally.
In 90% of cases, this is the answer.
If you want a specific height, wrap in SizedBox or Container.
Column(
children: [
Text("Header"),
SizedBox(
height: 200, // Fixed to 200 logical pixels
child: ListView(...),
),
Text("Footer"),
],
)
But this is bad for Responsive Design. It might look tiny on tablets or overflow on small phones.
The most misused property.
ListView(
shrinkWrap: true, // ⚠️ Warning!
physics: NeverScrollableScrollPhysics(),
...
)
shrinkWrap: true tells ListView: "Don't be infinite. Shrink yourself to fit your children."
Sounds good, but it has a fatal flaw:
Lazy Loading stops working.
If you have 100 items, it renders all 100. If 1,000, it renders 1,000 at once to calculate height.
As the list grows, you will experience severe lag (Jank). Avoid if possible.
What if the requirements are complex? "The header must scroll WITH the list." "The header should shrink/fade as I scroll (SliverAppBar)."
Here, you must abandon the Column + ListView structure.
Instead, use CustomScrollView and put everything as Slivers.
CustomScrollView(
slivers: [
// 1. Adapt normal widgets (Text) to Sliver World
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text("My Todo List", style: TextStyle(fontSize: 24)),
),
),
// 2. Sliver-optimized List
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text("Task $index")),
childCount: 100,
),
),
],
)
Sliver means a "slice" of the scrollable area. It's a high-performance system that only renders the viewport slice.
While Column + ListView separates scroll areas (fixed header, scrolling list), CustomScrollView treats everything as one unified scroll. Much better UX.
Is there an alternative to Expanded?
Yes, LimitedBox.
LimitedBox: "You can be infinite usually, but if your parent gives you Unbounded space (like Column), then force yourself to be max 300px." It's useful for widgets that should expand in a ScrollView but shrink in a Column.
The Scroll-in-Scroll Nightmare:
Never put a ListView inside a SingleChildScrollView with shrinkWrap: true.
It's creating an infinite canvas inside an infinite canvas. The Flutter engine weeps.
Always use CustomScrollView for mixing different scrollable contents.
What about a TabBar where each tab has a list (e.g., Instagram Profile)? The whole page scrolls, but the inner tab list also scrolls.
Enter NestedScrollView.
NestedScrollView(
headerSliverBuilder: (context, _) => [
SliverAppBar(title: Text("Profile"), pinned: true),
],
body: TabBarView(
children: [
ListView(...), // Tab 1
ListView(...), // Tab 2
],
),
)
This is Level 99 usage. But the principle is the same: Clarify "Who controls the scroll?"
If you have tabs with lists, swapping tabs destroys the list state (scroll position resets to top). Users hate this.
The Fix: Use AutomaticKeepAliveClientMixin.
class MyListPage extends StatefulWidget { ... }
class _MyListPageState extends State<MyListPage> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true; // Magic line
@override
Widget build(BuildContext context) {
super.build(context); // Must call this
return ListView(...);
}
}
This keeps the widget "alive" in memory even when it's off-screen.
Essential for TabBarView or PageView layouts.
Header fixed, only list scrolls?
-> Column + Expanded + ListView (Recommended).
Header scrolls WITH list?
-> Put Header as the first item in ListView, OR
-> CustomScrollView + SliverToBoxAdapter + SliverList (Best).
Very few items (< 10)?
-> Column + SingleChildScrollView. No need for ListView.
-> Or shrinkWrap: true (Last resort).
Tabs + Complex Scroll?
-> NestedScrollView.
The "Unbounded height" error isn't trying to annoy you. It's Flutter asking, "How do you want me to fit an infinite universe into a finite phone screen?"
Just put it in an Expanded box, and everyone is happy.