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

Software architect & product builder

Professional software work since my computer science studies. Ex-IBM, ex-PwC. Now building products with AI in Hamburg.