flutter-debugging
Use when encountering any bug, test failure, or unexpected behavior in Flutter - requires systematic investigation before proposing fixes
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when encountering any bug, test failure, or unexpected behavior in Flutter - requires systematic investigation before proposing fixes
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
| name | flutter-debugging |
| description | Use when encountering any bug, test failure, or unexpected behavior in Flutter - requires systematic investigation before proposing fixes |
Random fixes waste time and create new bugs. Quick patches mask underlying issues.
Core principle: ALWAYS find root cause before attempting fixes. Symptom fixes are failure.
Announce at start: "I'm using the flutter-debugging skill to investigate this issue."
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
If you haven't completed Phase 1, you cannot propose fixes.
Use for ANY Flutter technical issue:
Use this ESPECIALLY when:
// Basic logging (truncates long output)
print('Debug: $value');
// No truncation (preferred)
debugPrint('Debug: $value');
// Conditional debug logging
import 'package:flutter/foundation.dart';
if (kDebugMode) {
debugPrint('Only in debug mode: $value');
}
// Developer log with tags
import 'dart:developer';
log('API response', name: 'NetworkService', error: e);
# Open DevTools
flutter run --start-paused
# Then press 'd' or use DevTools button in IDE
DevTools Panels:
// Show widget boundaries
debugPaintSizeEnabled = true;
// Show baseline alignments
debugPaintBaselinesEnabled = true;
// Show repaint regions
debugRepaintRainbowEnabled = true;
// Programmatic breakpoint
import 'dart:developer';
debugger();
// Or use IDE breakpoints
BEFORE attempting ANY fix:
════════════════════════════════════════════════════════════
EXCEPTION CAUGHT BY WIDGETS LIBRARY
════════════════════════════════════════════════════════════
The following assertion was thrown building MyWidget:
'package:flutter/src/widgets/container.dart': Failed assertion: line 287
'child != null || decoration != null || constraints != null'
════════════════════════════════════════════════════════════
Don't skip past errors! They often contain the exact solution.
# Hot reload to reproduce
r # in terminal
# Hot restart (clears state)
R # in terminal
# Full restart
flutter run
# What changed recently?
git diff
# Recent commits
git log --oneline -10
# Diff with specific commit
git diff HEAD~3
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
debugPrint('=== MyWidget.build() ===');
debugPrint('context.mounted: ${context.mounted}');
final state = context.watch<MyState>();
debugPrint('state: $state');
return Container(...);
}
}
# Search for similar working code
grep -r "similar_pattern" lib/
// Reference: Working widget
class WorkingWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<WorkingBloc, WorkingState>(
builder: (context, state) => ...,
);
}
}
// Broken: My widget
class BrokenWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// What's different?
return BlocBuilder<MyBloc, MyState>(
builder: (context, state) => ...,
);
}
}
List every difference, however small:
State clearly:
"I think the issue is [X] because [Y]"
Example:
"I think the build error is because the BLoC is not provided above this widget in the widget tree"
Make the SMALLEST possible change:
// Before (broken)
Widget build(BuildContext context) {
final bloc = context.read<MyBloc>();
return ...;
}
// After (testing hypothesis)
Widget build(BuildContext context) {
debugPrint('Looking for MyBloc...');
try {
final bloc = context.read<MyBloc>();
debugPrint('Found: $bloc');
} catch (e) {
debugPrint('Error: $e');
}
return ...;
}
For Repository/DataSource issues (Priority 1):
test('should return user when API succeeds', () async {
// Arrange
when(mockApi.getUser(any)).thenAnswer((_) async => userModel);
// Act
final result = await repository.getUser('123');
// Assert
expect(result, equals(userEntity));
});
ONE change at a time:
// Fix the root cause identified in Phase 3
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => getIt<MyBloc>(),
child: BlocBuilder<MyBloc, MyState>(...),
);
}
}
# Run analysis
flutter analyze
# Run tests
flutter test
# Manual verification
flutter run
# Test the specific scenario
| Symptom | Common Root Cause |
|---|---|
| "No ancestor found" | Provider/BLoC not in widget tree above |
| "setState after dispose" | Async operation completing after widget disposed |
| "RenderBox not laid out" | Unbounded constraints (Column in Column, etc.) |
| "Null check operator" | Variable not initialized or API returned null |
| "Build during build" | setState called during build phase |
| "Ticker not disposed" | Missing with TickerProviderStateMixin or dispose |
If you catch yourself thinking:
ALL of these mean: STOP. Return to Phase 1.
After fixing the bug, you MUST invoke: → flutter-craft:flutter-verification
Verify the fix with flutter analyze, flutter test, and manual testing.
| Phase | Flutter Activities | Success Criteria |
|---|---|---|
| 1. Root Cause | Read error, reproduce, add debugPrint | Understand WHAT and WHY |
| 2. Pattern | Find working widgets, compare | Identify differences |
| 3. Hypothesis | Form theory, minimal test | Confirmed or new hypothesis |
| 4. Implementation | Create test (priority-based), fix, verify | Bug resolved, analysis clean |
Random fixes tend to thrash: each guess that fails contaminates the code and hides the original symptom. Root-cause-first debugging keeps the change set minimal, makes the fix verifiable, and avoids introducing new bugs while "trying things".
Creates a new Flutter project with Clean Architecture, domain pattern boilerplate, and production-ready setup
You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation using Clean Architecture principles.
Use when you have a written implementation plan to execute with review checkpoints
Use when facing 2+ independent Flutter tasks that can be worked on without shared state or sequential dependencies
Use when you have a design or requirements for a multi-step Flutter feature, before touching code
Use when executing Flutter implementation plans with independent tasks in the current session