Global Configuration
Static properties that configure behavior for all commands in your app. Set these once, typically in your app's main() function before calling runApp().
Overview
| Property | Type | Default | Purpose |
|---|---|---|---|
| globalExceptionHandler | Function? | null | Global error handler for all commands |
| globalErrors | Stream | N/A | Observable stream of all globally-routed errors |
| errorFilterDefault | ErrorFilter | GlobalIfNoLocalErrorFilter() | Default error filter |
| assertionsAlwaysThrow | bool | true | AssertionErrors bypass filters |
| reportAllExceptions | bool | false | Override filters, report all errors |
| detailedStackTraces | bool | true | Enhanced stack traces |
| loggingHandler | Function? | null | Handler for all command executions |
| reportErrorHandlerExceptionsToGlobalHandler | bool | true | Report error handler exceptions |
| useChainCapture | bool | false | Experimental detailed traces |
Complete Setup Example
Here's a typical setup configuring multiple global properties:
void main() {
// Configure global command_it settings before runApp
// 1. Global exception handler - called based on ErrorFilter configuration
Command.globalExceptionHandler = (error, stackTrace) {
debugPrint('Command error: ${error.error}');
debugPrint('Command: ${error.command}');
debugPrint('Parameter: ${error.paramData}');
// In production, send to Sentry
// Sentry.captureException(error.error, stackTrace: stackTrace);
};
// 2. Default error filter - determines error handling strategy
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
// 3. Logging handler - log all command executions
Command.loggingHandler = (commandName, result) {
if (kDebugMode) {
debugPrint(
'Command executed: ${result.isRunning ? "started" : "completed"}');
if (result.hasError) {
debugPrint(' Error: ${result.error}');
}
}
};
// 4. Detailed stack traces - strip framework noise (default: true)
Command.detailedStackTraces = true;
// 5. Assertions always throw - bypass error filters for assertions (default: true)
Command.assertionsAlwaysThrow = true;
// 6. Report all exceptions - ensure all errors reach global handler (for debugging)
Command.reportAllExceptions = kDebugMode;
// 7. Report error handler exceptions - if local error handler throws
Command.reportErrorHandlerExceptionsToGlobalHandler = true;
runApp(MyApp());
}globalExceptionHandler
Global error handler called for all command errors:
static void Function(CommandError<dynamic> error, StackTrace stackTrace)?
globalExceptionHandler;Set this once in your main() function to handle errors globally:
void main() {
Command.globalExceptionHandler = (error, stackTrace) {
loggingService.logError(error.error, stackTrace);
Sentry.captureException(error.error, stackTrace: stackTrace);
};
runApp(MyApp());
}When it's called:
- Depends on ErrorFilter configuration (default: when no local listeners exist)
- Always called when
reportAllExceptions: true
See: Error Handling - Global Error Handler for complete documentation including usage examples, error context details, and patterns.
globalErrors
Observable stream of all command errors routed to the global handler:
static Stream<CommandError<dynamic>> get globalErrorsPerfect for reactive error monitoring, analytics, crash reporting, and global UI notifications:
// Example: Global error toast in root widget
class MyApp extends WatchingWidget {
@override
Widget build(BuildContext context) {
registerStreamHandler<Stream<CommandError>, CommandError>(
target: Command.globalErrors,
handler: (context, snapshot, cancel) {
if (snapshot.hasData) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${snapshot.data!.error}')),
);
}
},
);
return MaterialApp(home: HomePage());
}
}Key points:
- Broadcast stream (multiple listeners supported)
- Emits when ErrorFilter routes errors to global handler
- Does NOT emit for debug-only
reportAllExceptions - Use with
globalExceptionHandlerfor comprehensive error handling
See: Error Handling - Global Errors Stream for complete documentation including use cases, stream behavior, and integration patterns.
errorFilterDefault
Default ErrorFilter used when no individual filter is specified per command:
static ErrorFilter errorFilterDefault = const GlobalIfNoLocalErrorFilter();Built-in Error Filters
GlobalIfNoLocalErrorFilter()(default) - Try local handlers first, fallback to globalLocalErrorFilter()- Only call local handlers (.errorsor.resultslisteners)GlobalErrorFilter()- Only call global exception handlerLocalAndGlobalErrorFilter()- Call both local and global handlers
Example
// Change default behavior for all commands
Command.errorFilterDefault = const LocalErrorFilter();See: Error Handling for complete ErrorFilter documentation and custom filters.
assertionsAlwaysThrow
AssertionErrors bypass ErrorFilters and are always rethrown:
static bool assertionsAlwaysThrow = true;Default: true (recommended)
Why This Exists
AssertionErrors indicate programming mistakes (like assert(condition) failures). They should be caught immediately during development, not silently swallowed by error filters.
Example
// Treat assertions like any other error (not recommended)
Command.assertionsAlwaysThrow = false;Recommendation: Keep this true to catch bugs early in development.
reportAllExceptions
Ensure every error calls globalExceptionHandler for debugging:
static bool reportAllExceptions = false;Default: false
How It Works
When true, every error calls globalExceptionHandler immediately, in addition to normal ErrorFilter processing.
Execution flow:
- Error occurs in command
globalExceptionHandleris called (ifreportAllExceptions: true)- ErrorFilter runs normally (determines local/global handling)
globalExceptionHandlermay be called again (if ErrorFilter says to)
Result: ErrorFilters are NOT bypassed - they still control local handlers and can trigger a second global handler call.
Common Pattern: Debug vs Production
// In main.dart
Command.reportAllExceptions = kDebugMode;What this does:
- Development (
kDebugMode = true): ALL errors reach global handler for visibility - Production (
kDebugMode = false): Only errors routed by ErrorFilter reach global handler
When to Use
- Debugging error handling - Ensure no errors are silently swallowed
- Development mode - See all errors regardless of ErrorFilter configuration
- Verifying crash reporting - Confirm all errors reach your analytics/crash reporting
Important: Potential Duplicate Calls
Command.reportAllExceptions = true;
Command.errorFilterDefault = const ErrorHandlerGlobal(); // Also calls global handler
// Result: globalExceptionHandler called TWICE for each error!
// 1. From reportAllExceptions
// 2. From ErrorFilterSolution: In production, use either reportAllExceptions OR ErrorFilters that call global, not both
detailedStackTraces
Clean up stack traces by filtering out framework noise:
static bool detailedStackTraces = true;Default: true (recommended)
What It Does
Uses the stack_trace package to filter and simplify stack traces.
Without detailedStackTraces (false) - raw stack trace:
#0 Object._throw (dart:core-patch/object_patch.dart:51)
#1 _Future._propagateToListeners (dart:async/future_impl.dart)
#2 _Future._completeError (dart:async/future_impl.dart)
#3 Zone.run (dart:async/zone.dart:1518)
#4 _rootRun (dart:async/zone.dart:1426)
... [50+ lines of framework internals]
#42 my_file.dart:42 ← Your actual code buried deepWith detailedStackTraces (true) - filtered and simplified:
#0 my_file.dart:42
#1 manager.dart:156
#2 widget.dart:89
... [Only relevant frames, framework noise removed]What gets filtered:
stack_tracepackage internal frames- Zone-related frames (async framework)
_rootRunand similar async framework callscommand_itinternal_runmethod frames
The result is also "tersed" - duplicate/redundant frames are removed.
Performance
Stack trace processing has minimal overhead. Only disable if profiling shows it's a bottleneck (rare).
loggingHandler
Handler called for every command execution (running, success, error):
static void Function(CommandResult<dynamic, dynamic> result)? loggingHandler;Default: null (no logging)
Analytics Integration Example
void setupLoggingHandler() {
Command.loggingHandler = (commandName, result) {
// Log all command executions to analytics
// Track command started
if (result.isRunning) {
analytics.logEvent('command_started', parameters: {
'command': commandName,
'has_parameter': result.paramData != null,
});
return;
}
// Track command completed
if (result.hasData) {
analytics.logEvent('command_success', parameters: {
'command': commandName,
'has_data': result.data != null,
'parameter': result.paramData?.toString(),
});
return;
}
// Track command error
if (result.hasError) {
analytics.logEvent('command_error', parameters: {
'command': commandName,
'error_type': result.error.runtimeType.toString(),
'parameter': result.paramData?.toString(),
'had_previous_data': result.data != null,
});
}
};
}What Data Is Available
CommandResult<TParam, TResult> provides:
.isRunning- Whether command is currently executing.hasData- Whether command has result data.hasError- Whether command failed.error- The error object (if any).data- The result data (if any).paramData- Parameter passed to command
Use Cases
- Analytics - Track command execution metrics
- Performance monitoring - Measure command execution time
- Debugging - Log all command activity
- Audit trails - Record user actions
reportErrorHandlerExceptionsToGlobalHandler
If a local error handler throws an exception, report it to globalExceptionHandler:
static bool reportErrorHandlerExceptionsToGlobalHandler = true;Default: true (recommended)
What This Catches
command.errors.listen((error, _) {
// Local error handler
throw Exception('Oops, error handler has a bug!'); // ← This gets caught
});With reportErrorHandlerExceptionsToGlobalHandler: true:
- Exception thrown in error handler is caught
- Sent to
globalExceptionHandler - Original error is stored in
CommandError.originalError
Why This Matters
Error handlers can have bugs too. This prevents error handling code from crashing your app.
useChainCapture
Experimental: Preserve stack traces across async boundaries to show where commands were called:
static bool useChainCapture = false;Default: false
What it does:
When enabled, preserves the call stack from where the command was invoked, even when the exception happens inside an async function. Without this, you often get an "async gap" - losing the stack trace context showing which code called the command.
Uses Dart's Chain.capture() mechanism to maintain the full stack trace across async boundaries.
Example without useChainCapture:
#0 ApiClient.fetch (api_client.dart:42)
#1 <async gap>Example with useChainCapture:
#0 ApiClient.fetch (api_client.dart:42)
#1 _fetchDataCommand.run (data_manager.dart:156)
#2 DataScreen.build.<anonymous> (data_screen.dart:89)
#3 ... (full call chain preserved)Status: Experimental feature that may change or be removed in future versions.
Not recommended for production use - may have performance implications.
Common Configuration Patterns
Development Mode
For maximum visibility during development:
void configureDevelopmentMode() {
// Development: verbose logging and error reporting
// Report ALL exceptions - even if error filters would swallow them
Command.reportAllExceptions = true;
// Detailed stack traces - strip framework noise for easier debugging
Command.detailedStackTraces = true;
// Assertions always throw - catch programming errors immediately
Command.assertionsAlwaysThrow = true;
// Log every command execution for debugging
Command.loggingHandler = (commandName, result) {
final timestamp = DateTime.now().toIso8601String();
debugPrint('[$timestamp] Command execution:');
debugPrint(' isRunning: ${result.isRunning}');
debugPrint(' hasData: ${result.hasData}');
debugPrint(' hasError: ${result.hasError}');
if (result.paramData != null) {
debugPrint(' param: ${result.paramData}');
}
if (result.hasError) {
debugPrint(' error: ${result.error}');
}
};
// Global error handler - print detailed error information
Command.globalExceptionHandler = (error, stackTrace) {
debugPrint('═══ COMMAND ERROR ═══');
debugPrint('Command: ${error.command}');
debugPrint('Error: ${error.error}');
debugPrint('Parameter: ${error.paramData}');
debugPrint('Stack trace:');
debugPrint(stackTrace.toString());
debugPrint('═══════════════════');
};
// Default filter: try local, fallback to global
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
}Characteristics:
- Report ALL errors (bypass filters)
- Verbose logging for every command
- Detailed stack traces
- Comprehensive error context
Production Mode
For production with crash reporting integration:
void configureProductionMode() {
// Production: crash reporting only, respect error filters
// Don't report all exceptions - respect error filters
Command.reportAllExceptions = false;
// Keep detailed stack traces for crash reports
Command.detailedStackTraces = true;
// Assertions should throw - catch critical bugs
Command.assertionsAlwaysThrow = true;
// Global error handler - send to Sentry
Command.globalExceptionHandler = (error, stackTrace) {
Sentry.captureException(
error.error,
stackTrace: stackTrace,
withScope: (scope) {
scope.setTag('command', error.command ?? 'unknown');
scope.setContexts('command_context', {
'parameter': error.paramData?.toString(),
'error_reaction': error.errorReaction.toString(),
});
},
);
};
// Default filter: local errors stay local, unhandled go global
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
// If error handler itself throws, report to global handler
Command.reportErrorHandlerExceptionsToGlobalHandler = true;
}Characteristics:
- Respect error filters (don't report everything)
- Send errors to crash reporting service
- Detailed stack traces for debugging production issues
- No verbose logging (keep production lean)
Testing Mode
For unit/integration tests:
void setupTestMode() {
// Disable all handlers to avoid side effects in tests
Command.globalExceptionHandler = null;
Command.loggingHandler = null;
// Let errors throw naturally for test assertions
Command.reportAllExceptions = false;
Command.errorFilterDefault = const ErrorHandlerNone();
}Property Interactions
reportAllExceptions Overrides Error Filters
When reportAllExceptions: true:
Command.reportAllExceptions = true;
Command.errorFilterDefault = const LocalErrorFilter(); // ← Ignored!Every error still goes to globalExceptionHandler, regardless of filter configuration.
assertionsAlwaysThrow Bypasses Everything
Command.assertionsAlwaysThrow = true; // Default
Command.errorFilterDefault = const ErrorHandlerNone(); // ← Ignored for assertions!AssertionErrors are always rethrown, even if filters would swallow them.
Error Handler Exception Reporting
Command.reportErrorHandlerExceptionsToGlobalHandler = true;
Command.globalExceptionHandler = (error, stackTrace) {
// Receives both:
// 1. Normal command errors
// 2. Exceptions thrown by local error handlers
if (error.originalError != null) {
// This error came from a buggy error handler
print('Error handler threw: ${error.error}');
print('Original error was: ${error.originalError}');
}
};Common Mistakes
❌️ Forgetting kDebugMode for reportAllExceptions
// WRONG: Always report all exceptions, even in production
Command.reportAllExceptions = true;Problem: Production app sends every error to crash reporting, creating noise.
Solution:
// ✅ Only in debug mode
Command.reportAllExceptions = kDebugMode;❌️ Not Accessing CommandError Properties
// WRONG: Only using the error object
Command.globalExceptionHandler = (commandError, stackTrace) {
Sentry.captureException(commandError.error, stackTrace: stackTrace);
// Missing valuable context!
};Solution:
// ✅ Use full CommandError context with Sentry
Command.globalExceptionHandler = (commandError, stackTrace) {
Sentry.captureException(
commandError.error,
stackTrace: stackTrace,
withScope: (scope) {
scope.setTag('command', commandError.command ?? 'unknown');
scope.setContexts('command_context', {
'parameter': commandError.paramData?.toString(),
'error_reaction': commandError.errorReaction.toString(),
});
},
);
};❌️ Using loggingHandler for Error Handling
// WRONG: Trying to handle errors in logging handler
Command.loggingHandler = (result) {
if (result.hasError) {
showErrorDialog(result.error); // Don't do this!
}
};Problem: loggingHandler is for observability, not error handling.
Solution:
// ✅ Use globalExceptionHandler for error handling
Command.globalExceptionHandler = (error, stackTrace) {
// Handle errors here
};
// ✅ Use loggingHandler only for metrics/analytics
Command.loggingHandler = (result) {
analytics.logEvent('command_executed', parameters: {
'has_error': result.hasError,
});
};❌️ Disabling detailedStackTraces Prematurely
// WRONG: Disabling without measuring
Command.detailedStackTraces = false; // "For performance"Problem: Stack trace processing has negligible overhead. Disabling makes debugging harder.
Solution:
// ✅ Only disable if profiling shows it's a bottleneck
Command.detailedStackTraces = true; // Keep the defaultSee Also
- Error Handling — Learn how
errorFilterDefaultandglobalExceptionHandlerwork with error filters, including custom filter creation - Command Properties — Instance-level properties that can override global defaults (like per-command error filters)
- Command Basics — Start here if you're new to command_it - learn how to create and run commands before configuring globals
- Troubleshooting — Common issues and solutions, including configuration problems