
Flutter Error Handling for the AI Era
Why I built moinsen_runapp — and how a 'Copy All' button revolutionizes the debugging workflow with coding assistants.
The Problem
We all know the drill: You're working with a coding assistant — Claude, Copilot, Cursor — and the AI generates code. You run it. Crash.
Now begins the dance:
- Take a screenshot of the error screen
- Open terminal, copy log output
- Dig out the stack trace from somewhere
- Formulate a prompt: "This error occurs when..."
- Copy everything together and send it to the AI
- Hope there's enough context
Five minutes per roundtrip. For complex bugs: dozens of roundtrips. Hours wasted on copy-paste gymnastics.
The Solution: One Button
What if you could just press one button and the coding assistant immediately understands what went wrong?
That was the idea behind moinsen_runapp.
import 'package:moinsen_runapp/moinsen_runapp.dart';
void main() {
moinsenRunApp(child: const MyApp());
}
One line. Your app now has:
- Three-layer error catching — nothing escapes
- Error deduplication — no "1000 identical errors in 3 seconds"
- Beautiful error screens — debug and release
- "Copy All" button — structured markdown bug report
The Game Changer: Copy All
Here's what the "Copy All" button generates:
## Error Report
**Runtime Type:** FormatException
**Message:** Invalid JSON at position 42
**Source:** zone (uncaught async)
**Count:** 3 occurrences
**First seen:** 2026-02-10 14:23:01
**Last seen:** 2026-02-10 14:23:04
### Stack Trace (App-filtered)
lib/services/api_client.dart:127 - parseResponse
lib/screens/home_screen.dart:45 - _loadData
lib/main.dart:23 - main
### Flutter Diagnostics
Flutter 3.19.0 • Dart 3.3.0
Device: iPhone 15 Pro (iOS 17.2)
Mode: debug
### Framework Context
[... relevant Flutter framework trace ...]
This is not a screenshot. This is structured context that any AI immediately understands.
Workflow: Before vs. After
Before (5+ minutes per bug)
Error → Screenshot → Terminal → Copy →
"The error is..." → Paste → Hope →
"More context?" → Screenshot again → ...
After (30 seconds)
Error → "Copy All" → Paste → Fix
I've been using this in all my projects for weeks now. The difference is dramatic.
Why Three-Layer Catching?
Flutter's standard error handling has holes:
| Error Type | Flutter Standard | moinsen_runapp |
|---|---|---|
| Widget Build Error | Red Screen of Death | ✅ Caught |
| Uncaught Async Error | App Crash | ✅ Caught |
| Platform Dispatcher Error | Silently ignored | ✅ Caught |
| Init Failure | App won't start | ✅ App starts anyway |
┌─────────────────────────────────────────────────┐
│ runZonedGuarded (Layer 3: Zone Catch-All) │
│ ┌───────────────────────────────────────────┐ │
│ │ PlatformDispatcher.onError (Layer 2) │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ FlutterError.onError (Layer 1) │ │ │
│ │ │ ┌───────────────────────────────┐ │ │ │
│ │ │ │ Your App │ │ │ │
│ │ │ └───────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Three nets. Nothing escapes.
Error Deduplication
You know the drill:
[ERROR] FormatException: Invalid JSON
[ERROR] FormatException: Invalid JSON
[ERROR] FormatException: Invalid JSON
[ERROR] FormatException: Invalid JSON
... (x 1000)
Your console is garbage. Your log file is garbage. You scroll forever to find the actual first error.
moinsen_runapp deduplicates automatically:
[ERROR] FormatException: Invalid JSON (3x in 2.1s)
Configurable via deduplicationWindow. Default: 2 seconds.
Release Error Screens
In production, you don't want to show stack traces. moinsen_runapp has three built-in variants:
| Variant | Style |
|---|---|
friendly | Wobbling animation, "Oops!" message, warm and approachable |
minimal | Clean, error icon, retry button, no animation |
illustrated | Full-screen CustomPainter, floating broken-link motif |
All with automatic dark/light mode support.
Or build your own:
moinsenRunApp(
config: RunAppConfig(
releaseScreenBuilder: (context, errors) {
return YourBrandedErrorScreen(errors: errors);
},
),
child: const MyApp(),
);
Integration with Sentry/Crashlytics
moinsenRunApp(
onError: (error, stackTrace) {
Sentry.captureException(error, stackTrace: stackTrace);
},
child: const MyApp(),
);
The onError callback fires for every error — including duplicates — so your external monitoring gets the full picture.
Installation
dependencies:
moinsen_runapp: ^0.1.0
Or via Git:
dependencies:
moinsen_runapp:
git:
url: https://github.com/moinsen-dev/moinsen_runapp.git
ref: main
Conclusion
The package is simple. A runApp() replacement. But the impact on the AI coding workflow is enormous.
Press a button, done.
No screenshot. No terminal scrolling. No prompt formulating.
Error → Copy All → Paste → Fix.
This is how debugging should work in the AI era.
Links
- pub.dev: moinsen_runapp
- GitHub: moinsen-dev/moinsen_runapp
- License: MIT
Built in Hamburg. Open Source. Just for Fun. 🖖
Tags:
FlutterDartAIDeveloper ToolsOpen Source
Ulrich Diedrichsen
AI Product Builder & Workshop Operator
40 years of software engineering. Ex-IBM, Ex-PwC. Now building real products with AI in Hamburg.

