Flutterで作業していると、UI関連のエラーに最も多く遭遇すると思われますが、そのたびにコンソールに表示されるエラーが長くて複雑で、何をどう解決すればよいか分からない状況が多かったです。そこで今回、出力メッセージを一つずつ確認しながら、どのようにアプローチすればよいかまとめてみようと思います!
エラーメッセージ#
════════ Exception caught by rendering library ═════════════════════════════════
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.
If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough vertical space for the children. In this case, consider using a Column or Wrap instead. Otherwise, consider using a CustomScrollView to concatenate arbitrary slivers into a single scrollable.
The relevant error-causing widget was:
ListView ListView:file:///Users/ittae/development/ittae/lib/src/features/calendar/presentation/attendance_pages/widgets/attendance_result.dart:21:21
When the exception was thrown, this was the stack:
#0 debugCheckHasBoundedAxis.<anonymous closure> (package:flutter/src/rendering/debug.dart:337:13)
#1 debugCheckHasBoundedAxis (package:flutter/src/rendering/debug.dart:396:4)
#2 RenderViewport.computeDryLayout (package:flutter/src/rendering/viewport.dart:1384:12)
#3 RenderBox.performResize (package:flutter/src/rendering/box.dart:2668:12)
#4 RenderObject.layout (package:flutter/src/rendering/object.dart:2587:9)
#5 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#6 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#7 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#8 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#9 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#10 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#11 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#12 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#13 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#14 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#15 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#16 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#17 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:61:11)
#18 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:985:73)
#19 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:1051:32)
#20 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#21 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:234:12)
#22 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#23 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:234:12)
#24 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#25 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:173:12)
#26 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1092:7)
#27 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:237:7)
#28 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:404:14)
#29 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#30 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#31 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#32 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#33 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1448:11)
#34 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#35 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#36 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#37 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#38 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#39 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#40 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#41 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:61:11)
#42 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:595:43)
#43 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:622:12)
#44 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#45 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#46 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#47 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#48 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#49 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#50 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#51 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#52 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#53 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#54 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#55 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#56 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3728:13)
#57 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#58 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#59 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#60 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1002:13)
#61 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1311:9)
#62 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#63 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#64 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#65 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#66 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#67 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#68 RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:569:11)
#69 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#70 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#71 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#72 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#73 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#74 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#75 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#76 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#77 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#78 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#79 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#80 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#81 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#82 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:111:21)
#83 RenderObject.layout (package:flutter/src/rendering/object.dart:2608:7)
#84 RenderView.performLayout (package:flutter/src/rendering/view.dart:281:14)
#85 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2446:7)
#87 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1065:15)
#88 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:602:23)
#89 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1164:13)
#90 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:468:5)
#91 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1397:15)
#92 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1318:9)
#93 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1040:9)
#94 PlatformDispatcher.scheduleWarmUpFrame.<anonymous closure> (dart:ui/platform_dispatcher.dart:837:16)
#98 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
(elided 3 frames from class _Timer and dart:async-patch)
The following RenderObject was being processed when the exception was fired: RenderViewport#d5613 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
needs compositing
parentData: <none> (can use size)
constraints: BoxConstraints(0.0<=w<=398.0, 0.0<=h<=Infinity)
size: MISSING
axisDirection: down
crossAxisDirection: right
offset: ScrollPositionWithSingleContext#b7b6f(offset: 0.0, range: null..null, viewport: null, ScrollableState, AlwaysScrollableScrollPhysics -> BouncingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#4402f, ScrollDirection.idle)
anchor: 0.0
center child: RenderSliverPadding#bbdeb NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: paintOffset=Offset(0.0, 0.0)
constraints: MISSING
geometry: null
padding: EdgeInsets.zero
textDirection: ltr
child: RenderSliverList#ccfb1 NEEDS-LAYOUT NEEDS-PAINT
parentData: paintOffset=Offset(0.0, 0.0)
constraints: MISSING
geometry: null
no children current live
RenderObject: RenderViewport#d5613 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
needs compositing
parentData: <none> (can use size)
constraints: BoxConstraints(0.0<=w<=398.0, 0.0<=h<=Infinity)
size: MISSING
axisDirection: down
crossAxisDirection: right
offset: ScrollPositionWithSingleContext#b7b6f(offset: 0.0, range: null..null, viewport: null, ScrollableState, AlwaysScrollableScrollPhysics -> BouncingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#4402f, ScrollDirection.idle)
anchor: 0.0
center child: RenderSliverPadding#bbdeb NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
parentData: paintOffset=Offset(0.0, 0.0)
constraints: MISSING
geometry: null
padding: EdgeInsets.zero
textDirection: ltr
child: RenderSliverList#ccfb1 NEEDS-LAYOUT NEEDS-PAINT
parentData: paintOffset=Offset(0.0, 0.0)
constraints: MISSING
geometry: null
no children current live
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderViewport#d5613 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2164 pos 12: 'hasSize'
The relevant error-causing widget was:
ListView ListView:file:///Users/ittae/development/ittae/lib/src/features/calendar/presentation/attendance_pages/widgets/attendance_result.dart:21:21
════════════════════════════════════════════════════════════════════════════════
この後ろに数個から数十個続くRenderBox was not laid outエラーは省略します!エラーメッセージの核心を把握する#
エラーメッセージのすべての内容を確認するのも良いですが、実際に開発した部分よりもフレームワークやSDKで処理される箇所で出力されるメッセージであることがほとんどです。そのため一つずつ確認しても、フレームワークのソースコードを把握していないと素早く役に立ちませんでした。
エラーの原因を簡単に把握する方法として、ログを解釈するのが役立ちます。長いエラーログの中で主に最初のエラーメッセージと発生したウィジェットの部分が最も重要です。Flutterの長いログは通常、複数段階のレンダリング過程を経て問題が発生した結果であり、最初に出たエラーが核心的なエラーである可能性が高いです。
全体の出力に集中するよりも、いくつかの重要なキーワードを探す必要があります。Flutterでエラーが出る主な理由として、あるウィジェットを追加・変更した際のレイアウト関連の問題である確率が高いです。
エラーの種類を調べる#
開発環境のデバッグコンソールを見ると、赤いものと青い文字のものがありますが、明らかに赤い部分を詳しく見る必要がありそうです。赤いメッセージの前後の説明も一緒に読むと、問題解決にさらに役立ちます。通常、出力が長いので全体的に目に入りにくいですが、最初のエラーメッセージを時間をかけて確認するのが、問題を素早く解決できる方法です。
このエラーメッセージはListViewを使っていた時に出たものです。ListViewは通常の状況ではうまく動きますが、ListViewをColumnの子として追加し、サイズを指定していなかったため、高さが無限大の状況となりエラーが発生したのでした。

解決方法#
Columnの子にあるListViewをExpandedで囲む
Expanded(
child: ListView(
children: [...],
),
)ContainerやSizedBoxウィジェットで高さを指定する
SizedBox(
height: 300.0, // 任意の高さ
child: ListView(
children: [...],
),
)ListViewにshrinkWrap: trueを追加する
ListView(
shrinkWrap: true,
children: [...],
)まとめ
- 最上部の最初のエラーメッセージに集中して確認する - ほとんどの解決策は最初のエラーに基づいて見つけられる
- エラーメッセージからウィジェットと行番号を追跡して、どこで問題が発生したか正確に把握する
- Flutter公式ドキュメントやStack Overflowを活用して類似のエラーの解決策を探す
Here and now...breathe and relax...in battle and in life.
— Dan Millman