| name | flutter-fix-layout-issues |
| description | Diagnose and fix Flutter layout constraint violations (RenderFlex overflow, unbounded height/width, ParentData misuse). Use when encountering layout exceptions, yellow-black overflow stripes, or red error screens. |
| metadata | {"platforms":"flutter","languages":"dart","category":"debugging"} |
Contents
Constraint Model
Flutter layout operates on a strict negotiation rule:
Constraints go down. Sizes go up. Parent sets position.
- A parent widget passes constraints (min/max width and height) to its child.
- The child determines its own size within those constraints.
- The parent decides the child's position.
Layout errors occur when this negotiation fails — typically when a parent provides unbounded constraints (infinite width or height) and the child attempts to expand infinitely.
Error Signature Catalog
| Error Message | Root Cause | Quick Fix |
|---|
Vertical viewport was given unbounded height | Scrollable (ListView, GridView) inside unconstrained vertical parent (Column) | Wrap in Expanded or SizedBox(height: ...) |
An InputDecorator...cannot have an unbounded width | TextField inside unconstrained horizontal parent (Row) | Wrap in Expanded |
A RenderFlex overflowed by X pixels | Child exceeds parent's allocated constraints | Wrap in Expanded, Flexible, or use overflow: TextOverflow.ellipsis |
Incorrect use of ParentData widget | Expanded outside Flex, Positioned outside Stack | Move widget to be direct child of correct parent |
RenderBox was not laid out | Cascading error — look upstream in stack trace | Fix the primary constraint error above it |
Rule: Always fix the first error in the stack trace. RenderBox was not laid out is almost always a cascading side effect.
Resolution Patterns
Decision Tree
Error detected
├── Contains "unbounded height"?
│ └── Wrap scrollable child in Expanded or SizedBox
├── Contains "unbounded width"?
│ └── Wrap TextField/InputDecorator in Expanded
├── Contains "RenderFlex overflowed"?
│ ├── Text overflow?
│ │ └── Add overflow: TextOverflow.ellipsis + Expanded wrapper
│ └── Widget overflow?
│ └── Wrap in Expanded or Flexible
├── Contains "ParentData"?
│ └── Ensure Expanded is direct child of Row/Column/Flex
│ Ensure Positioned is direct child of Stack
└── Contains "RenderBox was not laid out"?
└── IGNORE — fix the error above this one
Expanded vs Flexible vs SizedBox
| Widget | Behavior | Use When |
|---|
Expanded | Forces child to fill ALL remaining space | Child should stretch to fill |
Flexible | Allows child to be SMALLER than remaining space | Child has natural size but shouldn't overflow |
SizedBox | Provides absolute fixed constraints | You know the exact dimension needed |
ConstrainedBox | Sets min/max constraints | You need bounded flexibility |
Workflow: Fixing Layout Issues
Task Progress
Examples
Fixing Unbounded Height (ListView in Column)
Before (throws Vertical viewport was given unbounded height):
Column(
children: <Widget>[
const Text('Header'),
ListView(
children: const <Widget>[
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
],
),
],
)
After (resolved):
Column(
children: <Widget>[
const Text('Header'),
Expanded(
child: ListView(
children: const <Widget>[
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
],
),
),
],
)
Fixing Unbounded Width (TextField in Row)
Before (throws An InputDecorator...cannot have an unbounded width):
Row(
children: [
const Icon(Icons.search),
TextField(),
],
)
After (resolved):
Row(
children: [
const Icon(Icons.search),
Expanded(
child: TextField(),
),
],
)
Fixing RenderFlex Overflow (Text in Row)
Before (throws A RenderFlex overflowed by X pixels on the right):
Row(
children: [
const Icon(Icons.info),
Text('This is a very long text that will overflow the screen width'),
],
)
After (resolved):
Row(
children: [
const Icon(Icons.info),
Expanded(
child: Text(
'This is a very long text that will overflow the screen width',
overflow: TextOverflow.ellipsis,
),
),
],
)
Fixing ParentData Misuse
Before (throws Incorrect use of ParentData widget):
// Expanded must be a DIRECT child of Row/Column/Flex
Container(
child: Expanded( // WRONG: Expanded not inside a Flex
child: Text('Hello'),
),
)
After (resolved):
Row(
children: [
Expanded( // OK: Direct child of Row (a Flex widget)
child: Text('Hello'),
),
],
)