Flutter RenderFlex Overflow Fix & Example
A RenderFlex overflow occurs when a Row contains an unconstrained child widget, such as long Text or an unbounded Container, that exceeds the screen width. In this guide, you will learn why unbounded horizontal constraints cause assertion failures, inspect broken vs corrected Flutter layouts, and learn how to use Expanded, Flexible, or Wrap to fix layout overflow errors.
Why this happens: A RenderFlex overflowed by X pixels on the right error happens when a Row contains an unconstrained child (such as long Text or an unbounded Container) whose intrinsic width exceeds the screen or parent width.
How to fix it: Wrap the expanding child widget in an Expanded or Flexible widget so the Row provides bounded horizontal constraints, or replace the Row with a Wrap widget to allow children to flow onto multiple lines.
An e-commerce order status card or account header renders a verified account badge (fixed-width icon and spacing) next to dynamic customer names or localized product titles. In local testing, short sample strings like "John Doe" render without issues on standard test screens (390px+).
In production, long international names (e.g., "Dr. Christopher Alexander-Montgomery"), localized German or French phrases, or users with system accessibility font scaling enabled (1.5xβ2.0x) push the Row child beyond physical device boundaries, corrupting the layout and throwing fatal rendering assertions in debug builds.
Observed Symptom & Flutter Error Assertion
A RenderFlex overflowed by 48 pixels on the right with yellow/black hazard caution stripes.
βββββ‘ EXCEPTION CAUGHT BY RENDERING LIBRARY ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The following assertion was thrown during layout:
A RenderFlex overflowed by 48.0 pixels on the right.
The relevant error-causing widget was:
Row
lib/main.dart:18:14
The leading edge of the overflowing RenderFlex was:
RenderFlex#a94bc relayoutBoundary=up1 OVERFLOWING
creator: Row β SizedBox β Center β Scaffold
parentData: offset=Offset(0.0, 0.0); id=null (can use size)
constraints: BoxConstraints(w=320.0, h=56.0)
size: Size(368.0, 56.0)
direction: horizontal
mainAxisAlignment: start
crossAxisAlignment: center
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββDeclared Conditions
Row containing an unconstrained child (e.g. wide Text or Container) placed inside a bounded parent (e.g. 320px viewport or simulated 1.5x text scale).
A Row measures its children with unbounded horizontal constraints (maxWidth = double.infinity). An unconstrained Text widget measures its full intrinsic width without wrapping. When the sum of child widths exceeds the Row's incoming maxWidth, RenderFlex triggers an overflow assertion.
Wrap expanding children in Expanded or Flexible to pass bounded constraints along the flex main axis, or switch to Wrap for multi-line flow.
Architectural Deep Dive: Why This Failure Occurs in Flutter
Flutter Layout ProtocolIn Flutter's layout protocol ("Constraints go down, sizes go up, parents set positions"), a Row receives incoming BoxConstraints from its parent (e.g., maxWidth = 320.0). However, RenderFlex lays out non-flex children by passing them unbounded horizontal constraints (minWidth: 0.0, maxWidth: double.infinity).
The Text widget delegates to RenderParagraph, which measures its intrinsic text width without word wrapping because its incoming maxWidth is infinite. It reports its full unconstrained width (e.g., 368px) back up to RenderFlex. The Row sums the widths of all children (32px icon + 8px spacing + 368px text = 408px).
Because 408px exceeds the Row's allocated incoming maxWidth of 320px by 88px, and Row is an unscrollable single-axis flex container, RenderFlex.performLayout() sets _overflow = 88.0. In debug mode, Flutter asserts `!_overflow`, causing the familiar yellow-and-black hazard tape stripes.
Corrected: Bounded via Expanded
Wrapping the Text widget in Expanded gives it tight constraints bounded by the remaining row width, enabling automatic text wrapping or ellipsis.
- βWrap Text in Expanded to enforce remaining-width constraint
- βAdd overflow: TextOverflow.ellipsis and maxLines: 1 (or allow multi-line wrapping)
- βIcon remains fixed-width at 28px without displacement
import 'package:flutter/material.dart';
void main() => runApp(const FixedRowDemo());
class FixedRowDemo extends StatelessWidget {
const FixedRowDemo({super.key});
@override
Widget build(BuildContext context) {
const double containerWidth = 320;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Fixed: Bounded Row (320px)'),
backgroundColor: const Color(0xFF0D9488),
),
body: Center(
child: Container(
width: containerWidth,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFF2DD4BF),
width: 2,
),
),
child: Row(
children: [
Icon(
Icons.check_circle_rounded,
color: const Color(0xFF0D9488),
size: 28,
),
const SizedBox(width: 8),
// FIX: Expanded bounds child to remaining Row main-axis width!
const Expanded(
child: Text(
'This is an exceptionally long title text that cannot fit within 320px',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
),
],
),
),
),
),
);
}
}
Alternative Fixes & Decision Framework
Compare Flutter architectural solutions to select the ideal strategy for your UX requirements.
Row(
children: [
const Icon(Icons.account_circle, size: 28),
const SizedBox(width: 8),
Expanded(
child: Text(
userTitle,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
)When to choose: Choose when the text widget should take all available space along the row and push any trailing action icons to the far right edge.
Trade-offs: Forces the child to occupy all remaining width even if the text string is very short. If there are multiple Expanded widgets, available space is divided proportionally according to their flex factor.
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.account_circle, size: 28),
const SizedBox(width: 8),
Flexible(
fit: FlexFit.loose,
child: Text(
userTitle,
overflow: TextOverflow.ellipsis,
),
),
],
)When to choose: Choose when the Row should hug its content (shrink-wrap) without forcefully stretching across the full screen width, such as inside compact dialogs, chips, or tooltips.
Trade-offs: Child width is bounded by available space but will only take what its intrinsic content requires. Does not expand empty background space.
Wrap(
spacing: 8.0,
runSpacing: 4.0,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
const Icon(Icons.account_circle, size: 28),
Text(userTitle),
const Chip(label: Text('Verified')),
],
)When to choose: Choose when content items are discrete elements (tags, badges, chips) that should wrap down onto the next line rather than being truncated with ellipsis.
Trade-offs: Increases the overall vertical height of the parent container. Not suitable if the parent has a fixed or tight vertical height constraint.
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
const Icon(Icons.account_circle, size: 28),
const SizedBox(width: 8),
Text(userTitle),
],
),
)When to choose: Choose for data tables, metric cards, or horizontal tickers where every character must remain accessible without truncation and horizontal swiping is expected.
Trade-offs: Requires user gesture to discover off-screen content. May conflict with parent horizontal swipe gestures (tab views, carousels).
Architectural Limitations & Edge Cases
- β Nesting an Expanded inside another unconstrained flex container (e.g. Row inside another Row or horizontal ListView) causes a fatal unbounded constraints error.
- β Text widgets inside Expanded still require `softWrap: true` or `overflow: TextOverflow.ellipsis` if they exceed the remaining width; otherwise multi-line wrapping may cause vertical overflow.
- β Expanded only works as an immediate child of Flex, Row, or Column. Placing an intermediary Container between Row and Expanded throws an incorrect ParentDataWidget exception.
Common Mistakes to Avoid in Flutter
- β’Adding SingleChildScrollView(scrollDirection: Axis.horizontal) as a quick hack without considering responsive UX
- β’Hardcoding fixed pixel widths on Text or Container widgets instead of using flex weights with Expanded or Flexible
- β’Forgetting softWrap: true or overflow: TextOverflow.ellipsis on Text children inside flexible rows
Automated Verification Proof & Toolchain Evidence
Verification Contract: Automated test suite tests unconstrained Row at 280px width, verifies overflow assertion is trapped in isolated test zone, and verifies bounded Expanded child renders with zero layout errors across 280px, 320px, 390px, and 480px viewports.