Skip to main content
Back to Blog
Flutter Error Handling for the AI Era
FlutterDartAIDeveloper ToolsOpen Source

Flutter Error Handling for the AI Era

Ulrich Diedrichsen
Ulrich Diedrichsen
6 min read

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:

  1. Take a screenshot of the error screen
  2. Open terminal, copy log output
  3. Dig out the stack trace from somewhere
  4. Formulate a prompt: "This error occurs when..."
  5. Copy everything together and send it to the AI
  6. 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 TypeFlutter Standardmoinsen_runapp
Widget Build ErrorRed Screen of Death✅ Caught
Uncaught Async ErrorApp Crash✅ Caught
Platform Dispatcher ErrorSilently ignored✅ Caught
Init FailureApp 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:

VariantStyle
friendlyWobbling animation, "Oops!" message, warm and approachable
minimalClean, error icon, retry button, no animation
illustratedFull-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.



Built in Hamburg. Open Source. Just for Fun. 🖖

Tags:

FlutterDartAIDeveloper ToolsOpen Source
Ulrich Diedrichsen

Ulrich Diedrichsen

AI Product Builder & Workshop Operator

40 years of software engineering. Ex-IBM, Ex-PwC. Now building real products with AI in Hamburg.