一键导入
setup-global-catch-error
Configure Superpowers.globalCatchError for centralized error handling, logging, and error conversion
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Configure Superpowers.globalCatchError for centralized error handling, logging, and error conversion
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Add custom error handling with catchError to a mix() call for logging, error conversion, or suppression
Add internet connectivity checking before executing a Cubit method with optional retry
Add debounce to delay method execution until after a period of inactivity for search or validation
Add EffectQueue to state for triggering multiple sequential one-time UI effects
Add Effect fields to state class for one-time UI notifications like snackbars, navigation, or form clearing
Add error state handling to widgets using context.isFailed() and context.getException()
| name | setup-global-catch-error |
| description | Configure Superpowers.globalCatchError for centralized error handling, logging, and error conversion |
This skill configures Superpowers.globalCatchError for centralized error handling across all mix() calls.
Sets up a global error handler that:
mix() callsSet 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(...),
),
);
}
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
};
| Parameter | Type | Description |
|---|---|---|
error | Object | The exception that was thrown |
stackTrace | StackTrace | Where the error originated |
key | Object | The key from the mix() call |
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.');
};
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.');
};
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.');
};
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.');
};
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.
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.';
}
Reset the global handler between tests:
setUp(() {
Superpowers.clear(); // Removes globalCatchError and resets state
});
Ask the user: