Errores comunes de Flutter
Cómo reconocer y resolver errores comunes del framework de Flutter.
Introducción
#Esta página explica varios errores del framework de Flutter frecuentemente encontrados (incluidos errores de layout) y ofrece sugerencias sobre cómo resolverlos. Este es un documento vivo al que se añadirán más errores en futuras revisiones, y tus contribuciones son bienvenidas. Siéntete libre de abrir un issue o enviar un pull request para hacer que esta página sea más útil para ti y para la comunidad de Flutter.
Una pantalla roja o gris sólida al ejecutar tu app
#Normalmente llamada "pantalla roja (o gris) de la muerte", a veces es así como Flutter te permite saber que hay un error.
La pantalla roja puede aparecer cuando la app se ejecuta en modo debug o profile. La pantalla gris puede aparecer cuando la app se ejecuta en modo release.
Generalmente, estos errores ocurren cuando hay una excepción no capturada (y podrías necesitar otro bloque try-catch), o cuando hay algún error de renderizado, como un error de desbordamiento (overflow).
Los siguientes artículos proporcionan información útil sobre la depuración de este tipo de errores:
- Errores de Flutter desmitificados por Abishek
- Entendiendo y abordando la pantalla gris en Flutter por Christopher Nwosu-Madueke
- Flutter atascado en pantalla blanca por Kesar Bhimani
'Un RenderFlex se desbordó…'
#El desbordamiento de RenderFlex es uno de los errores del framework de Flutter frecuentemente encontrados, y probablemente ya te hayas topado con él.
What does the error look like?
Cuando sucede, aparecen franjas amarillas y negras, indicando el área de desbordamiento en la UI de la app. Además, se muestra un mensaje de error en la consola de depuración:
The following assertion was thrown during layout:
A RenderFlex overflowed by 1146 pixels on the right.
The relevant error-causing widget was
Row lib/errors/renderflex_overflow_column.dart:23
The overflowing RenderFlex has an orientation of Axis.horizontal.
The edge of the RenderFlex that is overflowing has been marked in the rendering
with a yellow and black striped pattern. This is usually caused by the contents
being too big for the RenderFlex.
(Additional lines of this message omitted)
How might you run into this error?
El error ocurre a menudo cuando una Column o un Row tiene un
widget hijo que no está restringido en su tamaño.
Por ejemplo,
el fragmento de código a continuación demuestra un escenario común:
Widget build(BuildContext context) {
return Row(
children: [
const Icon(Icons.message),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title', style: Theme.of(context).textTheme.headlineMedium),
const Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed '
'do eiusmod tempor incididunt ut labore et dolore magna '
'aliqua. Ut enim ad minim veniam, quis nostrud '
'exercitation ullamco laboris nisi ut aliquip ex ea '
'commodo consequat.',
),
],
),
],
);
}
En el ejemplo anterior,
la Column intenta ser más ancha que el espacio que el Row
(su padre) puede asignarle, causando un error de desbordamiento.
¿Por qué intenta hacer eso la Column?
Para entender este comportamiento de layout, necesitas saber
cómo realiza el layout el framework de Flutter:
"Para realizar el layout, Flutter recorre el árbol de renderizado en un recorrido primero en profundidad y pasa hacia abajo las restricciones de tamaño de padre a hijo… Los hijos responden pasando hacia arriba un tamaño a su objeto padre dentro de las restricciones que el padre estableció." – Visión general de la arquitectura de Flutter
En este caso, el widget Row no restringe el
tamaño de sus hijos, ni tampoco el widget Column.
Al carecer de restricciones de su widget padre, el segundo
widget Text intenta ser tan ancho como todos los caracteres
que necesita mostrar. El ancho autodeterminado del
widget Text es entonces adoptado por la Column, lo que
choca con la cantidad máxima de espacio horizontal que su padre,
el widget Row, puede proporcionar.
How to fix it?
Bueno, necesitas asegurarte de que la Column no intentará
ser más ancha de lo que puede ser. Para lograr esto,
necesitas restringir su ancho. Una forma de hacerlo es
envolver la Column en un widget Expanded:
return const Row(
children: [
Icon(Icons.message),
Expanded(
child: Column(
// code omitted
),
),
],
);
Otra forma es envolver la Column en un widget Flexible
y especificar un factor flex. De hecho,
el widget Expanded es equivalente al widget Flexible
con un factor flex de 1.0, como muestra
su código fuente.
Para comprender mejor cómo usar el widget Flex en layouts de Flutter,
consulta este video de 90 segundos de Widget of the Week
sobre el widget Flexible.
Further information:
Los recursos enlazados a continuación proporcionan más información sobre este error.
- Flexible (Flutter Widget of the Week)
- Cómo depurar problemas de diseño con el Flutter Inspector
- Entendiendo las restricciones
'RenderBox no fue dispuesto (laid out)'
#Si bien este error es bastante común, a menudo es un efecto secundario de un error primario que ocurrió anteriormente en el pipeline de renderizado.
What does the error look like?
El mensaje mostrado por el error se ve así:
RenderBox was not laid out:
RenderViewport#5a477 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
How might you run into this error?
Por lo general, el problema está relacionado con la violación de las restricciones de caja (box constraints), y debe resolverse proporcionando más información a Flutter sobre cómo te gustaría restringir los widgets en cuestión. Puedes obtener más información sobre cómo funcionan las restricciones en Flutter en la página Entendiendo las restricciones.
El error RenderBox no fue dispuesto (laid out) a menudo es
causado por uno de otros dos errores:
- 'A la ventana gráfica vertical (viewport) se le dio una altura no delimitada (unbounded)'
- 'Un InputDecorator...no puede tener un ancho no delimitado (unbounded)'
'A la ventana gráfica vertical (viewport) se le dio una altura no delimitada (unbounded)'
#Este es otro error de layout común con el que podrías toparte al crear una UI en tu app de Flutter.
What does the error look like?
El mensaje mostrado por el error se ve así:
The following assertion was thrown during performResize():
Vertical viewport was given unbounded height.
Viewports expand in the scrolling direction to fill their container.
In this case, a vertical viewport was given an unlimited amount of
vertical space in which to expand. This situation typically happens when a
scrollable widget is nested inside another scrollable widget.
(Additional lines of this message omitted)
How might you run into this error?
El error se causa a menudo cuando un ListView
(u otros tipos de widgets desplazables como GridView)
se coloca dentro de una Column. Un ListView toma todo
el espacio vertical disponible para él,
a menos que esté restringido por su widget padre.
Sin embargo, una Column no impone ninguna restricción
en la altura de sus hijos por defecto.
La combinación de los dos comportamientos conduce al fallo al
determinar el tamaño del ListView.
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
const Text('Header'),
ListView(
children: const <Widget>[
ListTile(leading: Icon(Icons.map), title: Text('Map')),
ListTile(leading: Icon(Icons.subway), title: Text('Subway')),
],
),
],
),
);
}
How to fix it?
Para solucionar este error, especifica qué tan alto debe ser el ListView.
Para hacerlos tan alto como el espacio restante en la Column,
envuélvelo usando un widget Expanded (como se muestra en el siguiente ejemplo).
De lo contrario, especifica una altura absoluta usando un widget SizedBox
o una altura relativa usando un widget Flexible.
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
const Text('Header'),
Expanded(
child: ListView(
children: const <Widget>[
ListTile(leading: Icon(Icons.map), title: Text('Map')),
ListTile(leading: Icon(Icons.subway), title: Text('Subway')),
],
),
),
],
),
);
}
Further information:
Los recursos enlazados a continuación proporcionan más información sobre este error.
'Un InputDecorator...no puede tener un ancho no delimitado (unbounded)'
#El mensaje de error sugiere que también está relacionado con las restricciones de caja (box constraints), las cuales son importantes de entender para evitar muchos de los errores más comunes del framework de Flutter.
What does the error look like?
El mensaje mostrado por el error se ve así:
The following assertion was thrown during performLayout():
An InputDecorator, which is typically created by a TextField, cannot have an
unbounded width.
This happens when the parent widget does not provide a finite width constraint.
For example, if the InputDecorator is contained by a `Row`, then its width must
be constrained. An `Expanded` widget or a SizedBox can be used to constrain the
width of the InputDecorator or the TextField that contains it.
(Additional lines of this message omitted)
How might you run into the error?
Este error ocurre, por ejemplo, cuando un Row contiene un
TextFormField o un TextField pero este último no tiene
restricción de ancho.
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Unbounded Width of the TextField')),
body: const Row(children: [TextField()]),
),
);
}
How to fix it?
Como sugiere el mensaje de error,
soluciona este error restringiendo el campo de texto
usando un widget Expanded o SizedBox.
El siguiente ejemplo demuestra el uso de un widget Expanded:
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Unbounded Width of the TextField')),
body: Row(children: [Expanded(child: TextFormField())]),
),
);
}
'Uso incorrecto del widget ParentData'
#Este error se debe a la falta de un widget padre esperado.
What does the error look like?
El mensaje mostrado por el error se ve así:
The following assertion was thrown while looking for parent data:
Incorrect use of ParentDataWidget.
(Some lines of this message omitted)
Usually, this indicates that at least one of the offending ParentDataWidgets
listed above is not placed directly inside a compatible ancestor widget.
How might you run into the error?
Si bien los widgets de Flutter son generalmente flexibles en cómo se pueden componer juntos en una UI, un pequeño subconjunto de esos widgets espera widgets padre específicos. Cuando esta expectativa no se puede satisfacer en tu árbol de widgets, es probable que te encuentres con este error.
Aquí hay una lista incompleta de widgets que esperan widgets padre específicos dentro del framework de Flutter. Siéntete libre de enviar un PR (usando el icono de doc en la esquina superior derecha de la página) para ampliar esta lista.
| Widget | Widget(s) padre esperado(s) |
|---|---|
Flexible |
Row, Column o Flex |
Expanded (un Flexible especializado) |
Row, Column o Flex |
Positioned | Stack |
TableCell | Table |
How to fix it?
La solución debería ser obvia una vez que sepas qué widget padre falta.
'setState llamado durante la construcción (build)'
#El método build en tu código de Flutter no es
un buen lugar para llamar a setState,
ya sea directa o indirectamente.
What does the error look like?
Cuando ocurre el error, se muestra el siguiente mensaje en la consola:
The following assertion was thrown building DialogPage(dirty, dependencies:
[_InheritedTheme, _LocalizationsScope-[GlobalKey#59a8e]],
state: _DialogPageState#f121e):
setState() or markNeedsBuild() called during build.
This Overlay widget cannot be marked as needing to build because the framework
is already in the process of building widgets.
(Additional lines of this message omitted)
How might you run into the error?
En general, este error ocurre cuando el método setState
es llamado dentro del método build.
Un escenario común donde ocurre este error es al
intentar activar un Dialog desde dentro del
método build. Esto suele estar motivado por la necesidad de
mostrar información inmediatamente al usuario,
pero setState nunca debería llamarse desde un método build.
El siguiente fragmento parece ser un culpable común de este error:
Widget build(BuildContext context) {
// Don't do this.
showDialog(
context: context,
builder: (context) {
return const AlertDialog(title: Text('Alert Dialog'));
},
);
return const Center(
child: Column(children: <Widget>[Text('Show Material Dialog')]),
);
}
Este código no hace una llamada explícita a setState,
pero es llamado por showDialog.
El método build no es el lugar adecuado para llamar a
showDialog porque build puede ser llamado por el
framework para cada frame, por ejemplo, durante una animación.
How to fix it?
Una forma de evitar este error es usar la API de Navigator
para activar el diálogo como una ruta (route). En el siguiente ejemplo,
hay dos páginas. La segunda página tiene un
diálogo para ser mostrado al entrar.
Cuando el usuario solicita la segunda página al
hacer clic en un botón en la primera página,
el Navigator empuja (pushes) dos rutas: una
para la segunda página y otra para el diálogo.
class FirstScreen extends StatelessWidget {
const FirstScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('First Screen')),
body: Center(
child: ElevatedButton(
child: const Text('Launch screen'),
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
// Immediately show a dialog upon loading the second screen.
Navigator.push(
context,
PageRouteBuilder(
barrierDismissible: true,
opaque: false,
pageBuilder: (_, anim1, anim2) => const MyDialog(),
),
);
},
),
),
);
}
}
El ScrollController está adjunto a múltiples vistas de desplazamiento
#
Este error puede ocurrir cuando múltiples widgets de desplazamiento
(como ListView) aparecen en la
pantalla al mismo tiempo. Es más probable que
este error ocurra en una app web o de escritorio,
que en una app móvil ya que es raro encontrar
este escenario en móviles.
Para obtener más información y aprender cómo solucionarlo,
consulta el siguiente video sobre
PrimaryScrollController:
Referencias
#Para aprender más sobre cómo depurar errores, especialmente errores de layout en Flutter, consulta los siguientes recursos:
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-11. Ver código fuente oreportar un problema.