smithery/marcglasberg

setup-global-catch-error

Configure Superpowers.globalCatchError for centralized error handling, logging, and error conversion

Installation

$ npx skills add smithery/marcglasberg --skill setup-global-catch-error

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/marcglasberg · top by installs.

npx skills add smithery/marcglasberg

Browse all from smithery/marcglasberg

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,903 B
  • docs SUMMARY.md 132 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Setup Global Error Handler

This skill configures Superpowers.globalCatchError for centralized error handling across all mix() calls.

What This Skill Does

Sets up a global error handler that:

  • Catches all unhandled errors from mix() calls
  • Logs errors to analytics/crash reporting
  • Converts technical errors to user-friendly messages
  • Provides consistent error handling across the app

Instructions

Step 1: Configure in main()

Set Superpowers.globalCatchError before runApp():

import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:flutter/material.dart';

void main() {
  Superpowers.globalCatchError = (error, stackTrace, key) {
    // Handle the error
  };

  runApp(
    Superpowers(
      child: MaterialApp(...),
    ),
  );
}

Step 2: Choose Response Strategy

The handler can respond in three ways:

1. Suppress (return normally): Error is silenced, no dialog shown

Superpowers.globalCatchError = (error, stackTrace, key) {
  logError(error, stackTrace);
  // Return without throwing = error suppressed
};

2. Show Dialog (throw UserException): Displays error dialog to user

Superpowers.globalCatchError = (error, stackTrace, key) {
  logError(error, stackTrace);
  throw UserException('Something went wrong');
};

3. Crash (throw other exception): App crashes (useful in debug mode)

Superpowers.globalCatchError = (error, stackTrace, key) {
  if (kDebugMode) throw error;  // Crash in debug
  throw UserException('Something went wrong');  // Dialog in release
};

Handler Parameters

Parameter Type Description
error Object The exception that was thrown
stackTrace StackTrace Where the error originated
key Object The key from the mix() call

Common Patterns

Log All Errors

Superpowers.globalCatchError = (error, stackTrace, key) {
  // Log to your analytics service
  analyticsService.logError(
    error: error,
    stackTrace: stackTrace,
    context: {'key': key.toString()},
  );

  // Show generic message
  if (error is UserException) throw error;
  throw UserException('Something went wrong. Please try again.');
};

Convert API Errors

Superpowers.globalCatchError = (error, stackTrace, key) {
  logError(error, stackTrace);

  // Firebase Auth errors
  if (error is FirebaseAuthException) {
    switch (error.code) {
      case 'user-not-found':
        throw UserException('No account found with this email.');
      case 'wrong-password':
        throw UserException('Incorrect password.');
      case 'user-disabled':
        throw UserException('This account has been disabled.');
      case 'too-many-requests':
        throw UserException('Too many attempts. Try again later.');
      default:
        throw UserException('Authentication failed.');
    }
  }

  // Dio/HTTP errors
  if (error is DioException) {
    switch (error.response?.statusCode) {
      case 401:
        throw UserException('Session expired. Please log in again.');
      case 403:
        throw UserException('You don\'t have permission for this action.');
      case 404:
        throw UserException('The requested item was not found.');
      case 500:
        throw UserException('Server error. Please try again later.');
      default:
        throw UserException('Network error. Check your connection.');
    }
  }

  // Network errors
  if (error is SocketException || error is TimeoutException) {
    throw UserException('Could not connect to the server.');
  }

  // Pass through UserExceptions
  if (error is UserException) throw error;

  // Generic fallback
  throw UserException('Something went wrong. Please try again.');
};

Debug vs Release Mode

Superpowers.globalCatchError = (error, stackTrace, key) {
  // Always log
  logger.error('Error in $key', error, stackTrace);

  // In debug mode, crash to see the error
  if (kDebugMode) {
    throw error;
  }

  // In release, show friendly message
  if (error is UserException) throw error;
  throw UserException('Something went wrong. Please try again.');
};

With Crash Reporting (Crashlytics/Sentry)

Superpowers.globalCatchError = (error, stackTrace, key) {
  // Report to Crashlytics
  FirebaseCrashlytics.instance.recordError(
    error,
    stackTrace,
    reason: 'Error in mix call: $key',
  );

  // Or report to Sentry
  Sentry.captureException(
    error,
    stackTrace: stackTrace,
    hint: Hint.withMap({'key': key.toString()}),
  );

  // Convert to user-friendly message
  if (error is UserException) throw error;
  throw UserException('An error occurred. Our team has been notified.');
};

Error Flow

Errors flow through handlers in order:

Error in mix()
       ↓
1. Local catchError (in mix call)
       ↓ (if rethrows)
2. Config catchError (in MixConfig)
       ↓ (if rethrows)
3. globalCatchError
       ↓
   ┌───┴───┐
   │       │
returns  throws
   │       │
   ↓       ↓
suppressed → isFailed() = true
             UserExceptionDialog shows

If any handler suppresses (returns without throwing), subsequent handlers don't run.

Complete Example

import 'package:bloc_superpowers/bloc_superpowers.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() {
  _setupGlobalErrorHandler();

  runApp(
    Superpowers(
      child: MyApp(),
    ),
  );
}

void _setupGlobalErrorHandler() {
  Superpowers.globalCatchError = (error, stackTrace, key) {
    // 1. Log all errors
    _logError(error, stackTrace, key);

    // 2. In debug mode, rethrow to see full error
    if (kDebugMode && error is! UserException) {
      print('Error in $key: $error\n$stackTrace');
    }

    // 3. Convert known errors to user-friendly messages
    final userMessage = _convertToUserMessage(error);
    throw UserException(userMessage).addCause(error);
  };
}

void _logError(Object error, StackTrace stackTrace, Object key) {
  // Log to your service
  analyticsService.logError(
    error: error,
    stackTrace: stackTrace,
    context: {'mix_key': key.toString()},
  );
}

String _convertToUserMessage(Object error) {
  // Pass through existing user messages
  if (error is UserException) return error.message;

  // Firebase Auth
  if (error is FirebaseAuthException) {
    return switch (error.code) {
      'user-not-found' => 'No account found with this email.',
      'wrong-password' => 'Incorrect password.',
      'email-already-in-use' => 'An account already exists with this email.',
      _ => 'Authentication failed. Please try again.',
    };
  }

  // Network errors
  if (error is SocketException) {
    return 'No internet connection.';
  }
  if (error is TimeoutException) {
    return 'Request timed out. Please try again.';
  }

  // HTTP errors
  if (error is DioException) {
    return switch (error.response?.statusCode) {
      401 => 'Please log in to continue.',
      403 => 'You don\'t have permission for this action.',
      404 => 'The requested item was not found.',
      >= 500 => 'Server error. Please try again later.',
      _ => 'Network error. Please check your connection.',
    };
  }

  // Generic fallback
  return 'Something went wrong. Please try again.';
}

Testing

Reset the global handler between tests:

setUp(() {
  Superpowers.clear();  // Removes globalCatchError and resets state
});

User Preferences

Ask the user:

  1. What error types need conversion? (Firebase, Dio, custom API errors)
  2. Should errors be logged? (to analytics, Crashlytics, Sentry)
  3. Debug mode behavior? (crash to see error, or show dialog)