Beginner · Lesson 10 · 11 min read
Debugging: Reading Errors and Using DevTools
Decode Flutter's most common error messages, use breakpoints and the widget inspector, and build a repeatable approach to fixing bugs.
Updated August 1, 2026
What you will learn
- Read a Flutter error message and find the real cause
- Recognise and fix the most common runtime errors
- Use breakpoints and the DevTools widget inspector
- Log usefully without slowing down release builds
Flutter's error messages are unusually good — they often tell you exactly which widget failed and suggest a fix. The skill is knowing where to look in a wall of red text, and that skill is mostly pattern recognition.
How to read an error
Flutter frames every error the same way. Read it in this order:
- The first line names the exception type and the short reason. This is usually enough.
- "The relevant error-causing widget was" tells you which of your widgets triggered it — skip past framework frames to find this.
- The stack trace, read top-down, looking for the first line pointing at a file in your
lib/folder. That is where to put a breakpoint. - The suggestions at the bottom. Flutter frequently names the exact fix.
The errors you will actually hit
| Message | Cause | Fix |
|---|---|---|
A RenderFlex overflowed by N pixels | A child wanted more space than its Row/Column had | Wrap the child in Expanded/Flexible, or make the parent scrollable |
Vertical viewport was given unbounded height | A ListView inside a Column | Wrap the ListView in Expanded, or give it a fixed height |
setState() called after dispose() | An async callback returned after the widget was removed | if (!mounted) return; before the setState |
setState() or markNeedsBuild() called during build | State mutated while building | Move the call into a callback or initState |
Null check operator used on a null value | A ! on something that was null | Use ?./??, or find why the value is missing |
No Material widget found | A Material widget outside a Scaffold/Material | Wrap it in Material or Scaffold |
Unable to load asset | Asset missing from pubspec, or a typo in the path | Declare it under flutter: assets:, then full restart |
Incorrect use of ParentDataWidget | Expanded/Positioned used outside Flex/Stack | Only use them as direct children of the right parent |
Print debugging, done properly
import 'package:flutter/foundation.dart';
// debugPrint throttles output so Android does not drop lines
debugPrint('Loaded ${articles.length} articles');
// kDebugMode is a compile-time constant — this whole block is
// removed from release builds by tree shaking
if (kDebugMode) {
debugPrint('Auth token: $token');
}
// Structured logging, filterable by name in DevTools
import 'dart:developer' as developer;
developer.log(
'Fetch failed',
name: 'api.articles',
error: error,
stackTrace: stackTrace,
);Breakpoints beat print statements
- Click the gutter next to a line in VS Code or Android Studio and run in debug mode. Execution pauses and you can inspect every variable in scope.
- Conditional breakpoints — right-click a breakpoint and add an expression like
index == 47to stop only on the case that misbehaves. - Step over / step into / step out move through code one line at a time; the call stack panel shows how you arrived.
- Add an expression to the Watch panel to see it update as you step.
// Assertions run only in debug builds — a cheap way to catch bad state early
assert(items.isNotEmpty, 'Items must not be empty when building the list');
// Pause the debugger from code, at exactly the moment you care about
import 'dart:developer';
if (article.id == suspiciousId) {
debugger(); // execution stops here when debugging
}DevTools
DevTools opens automatically from the URL printed by flutter run, or through your IDE's Flutter panel. The tabs you will use most as a beginner:
- Widget Inspector — click any widget on screen and jump to the code that built it. Its layout view shows the constraints and size of every box, which makes overflow bugs obvious.
- Debug Console — your logs, grouped and filterable.
- Network — every HTTP request with headers, timing and response body.
- Performance — frame times, for when scrolling feels rough.
- Memory — object counts over time, for hunting leaks.
import 'package:flutter/rendering.dart';
void main() {
// Outlines every render box — instant visual layout debugging
debugPaintSizeEnabled = true;
// Highlights tap targets
debugPaintPointersEnabled = true;
runApp(const MyApp());
}A repeatable method
- Reproduce it reliably. A bug you cannot trigger on demand cannot be verified as fixed.
- Narrow it down. Comment out half the screen. Does it still happen? Repeat. This finds the culprit faster than reading code.
- Read the actual error, not the first line of red you see. Scroll up — the real cause is often above the noise.
- Form one hypothesis and test it. Changing four things at once means you will not know which fixed it.
- Check the obvious things: is it a hot-reload artifact? Try a hot restart. Still there?
flutter clean && flutter pub get. - Write a test that fails on the bug once you find it, so it cannot come back silently.
Official references
Continue with the primary Flutter and Dart documentation for this topic.
Key takeaways
- Find "the relevant error-causing widget" line — it names your code, not the framework's.
- Most beginner errors are one of about eight patterns; learn them and the fixes are instant.
- Use
debugPrintandkDebugMode, never rawprintwith sensitive values. - The DevTools widget inspector shows real constraints and sizes — it ends layout guesswork.
Practice
Break it on purpose
Deliberately create four errors: a Row overflow, a ListView in a Column, a setState after dispose, and a null check on a null value. For each, read the message, write down which line told you the cause, then fix it. You will recognise all four instantly afterwards.
Show hints
- For setState-after-dispose, await a long Future then setState, and navigate away while it runs.
- Turn on
debugPaintSizeEnabledwhile fixing the overflow to see the boxes involved.
Lesson 3
Profiling and Fixing Performance
Find real jank with DevTools, understand UI versus raster thread costs, and apply the fixes that actually move the numbers.
Lesson 9
Using Packages from pub.dev
Add dependencies, read version constraints, and judge whether a package is safe to depend on before you build your app on top of it.
Lesson 11
Build a To-Do App from Scratch
Turn widgets, lists, text input and local state into a complete first Flutter app with add, complete, filter and delete flows.