Chapter 7.3: Error Reference
This chapter provides a comprehensive reference for all EventCore error types, error codes, and troubleshooting guidance. Use this reference to understand and resolve errors in your EventCore applications.
Error Categories
EventCore errors are organized into several categories based on their origin and nature:
- Command Errors - Errors during command execution
- Event Store Errors - Errors from event store operations
- Projection Errors - Errors in projection processing
- Validation Errors - Input validation failures
- Configuration Errors - Configuration and setup issues
- Network Errors - Network and connectivity issues
- Serialization Errors - Data serialization/deserialization issues
Command Errors
CommandError
The primary error type for command execution failures.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum CommandError { #[error("Validation failed: {message}")] ValidationFailed { message: String }, #[error("Business rule violation: {rule} - {message}")] BusinessRuleViolation { rule: String, message: String }, #[error("Concurrency conflict on streams: {streams:?}")] ConcurrencyConflict { streams: Vec<StreamId> }, #[error("Stream not found: {stream_id}")] StreamNotFound { stream_id: StreamId }, #[error("Unauthorized: {permission}")] Unauthorized { permission: String }, #[error("Timeout after {duration:?}")] Timeout { duration: Duration }, #[error("Stream access denied: cannot write to {stream_id}")] StreamAccessDenied { stream_id: StreamId }, #[error("Maximum discovery iterations exceeded: {iterations}")] MaxIterationsExceeded { iterations: usize }, #[error("Event store error: {source}")] EventStoreError { #[from] source: EventStoreError }, #[error("Serialization error: {message}")] SerializationError { message: String }, #[error("Internal error: {message}")] InternalError { message: String }, } }
Error Codes and Solutions
CE001: ValidationFailed
Error: Validation failed: StreamId cannot be empty
Code: CE001
Cause: Input validation failed during command construction or execution. Solution:
- Check input parameters for correct format and constraints
- Ensure all required fields are provided
- Verify string lengths and format requirements
CE002: BusinessRuleViolation
Error: Business rule violation: insufficient_balance - Account balance $100.00 is less than transfer amount $150.00
Code: CE002
Cause: Business logic constraints were violated. Solution:
- Review business rules and ensure command logic respects them
- Check application state before executing commands
- Implement proper validation in command handlers
CE003: ConcurrencyConflict
Error: Concurrency conflict on streams: ["account-123", "account-456"]
Code: CE003
Cause: Multiple commands attempted to modify the same streams simultaneously. Solution:
- Implement retry logic with exponential backoff
- Consider command design to reduce conflicts
- Use optimistic concurrency control patterns
CE004: StreamNotFound
Error: Stream not found: account-nonexistent
Code: CE004
Cause: Command attempted to read from a stream that doesn’t exist. Solution:
- Verify stream IDs are correct
- Check if the resource exists before referencing it
- Implement proper error handling for missing resources
CE005: Unauthorized
Error: Unauthorized: write_account_events
Code: CE005
Cause: Insufficient permissions to execute the command. Solution:
- Verify user authentication and authorization
- Check role-based access control configuration
- Ensure proper security context is set
CE006: Timeout
Error: Timeout after 30s
Code: CE006
Cause: Command execution exceeded configured timeout. Solution:
- Check system performance and database connectivity
- Increase timeout configuration if appropriate
- Optimize command logic and database queries
CE007: StreamAccessDenied
Error: Stream access denied: cannot write to protected-stream-123
Code: CE007
Cause: Command attempted to write to a stream it didn’t declare. Solution:
- Add the stream to the command’s
read_streams()
method - Verify command design follows EventCore stream access patterns
- Check for typos in stream ID generation
CE008: MaxIterationsExceeded
Error: Maximum discovery iterations exceeded: 10
Code: CE008
Cause: Stream discovery loop exceeded configured maximum iterations. Solution:
- Review command logic for potential infinite discovery loops
- Increase
max_discovery_iterations
if legitimate - Optimize stream discovery patterns
Command Execution Flow Errors
These errors occur during specific phases of command execution:
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum ExecutionPhaseError { #[error("Stream reading failed: {message}")] StreamReadError { message: String }, #[error("State reconstruction failed: {message}")] StateReconstructionError { message: String }, #[error("Command handling failed: {message}")] CommandHandlingError { message: String }, #[error("Event writing failed: {message}")] EventWritingError { message: String }, #[error("Stream discovery failed: {message}")] StreamDiscoveryError { message: String }, } }
Event Store Errors
EventStoreError
Errors from event store operations.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum EventStoreError { #[error("Version conflict: expected {expected:?}, got {actual}")] VersionConflict { expected: ExpectedVersion, actual: EventVersion, }, #[error("Stream not found: {stream_id}")] StreamNotFound { stream_id: StreamId }, #[error("Connection failed: {message}")] ConnectionFailed { message: String }, #[error("Database error: {source}")] DatabaseError { #[from] source: sqlx::Error, }, #[error("Serialization error: {message}")] SerializationError { message: String }, #[error("Transaction failed: {message}")] TransactionError { message: String }, #[error("Migration error: {message}")] MigrationError { message: String }, #[error("Configuration error: {message}")] ConfigurationError { message: String }, #[error("Timeout error: operation timed out after {duration:?}")] TimeoutError { duration: Duration }, #[error("Connection pool exhausted")] ConnectionPoolExhausted, #[error("Invalid event data: {message}")] InvalidEventData { message: String }, } }
Error Codes and Solutions
ES001: VersionConflict
Error: Version conflict: expected Exact(5), got 7
Code: ES001
Cause: Optimistic concurrency control detected concurrent modification. Solution:
- Implement retry logic in command execution
- Consider command design to reduce conflicts
- Use appropriate
ExpectedVersion
strategy
ES002: ConnectionFailed
Error: Connection failed: Failed to connect to database at postgresql://localhost/eventcore
Code: ES002
Cause: Unable to establish database connection. Solution:
- Verify database is running and accessible
- Check connection string configuration
- Verify network connectivity and firewall rules
ES003: ConnectionPoolExhausted
Error: Connection pool exhausted
Code: ES003
Cause: All database connections in the pool are in use. Solution:
- Increase
max_connections
in pool configuration - Check for connection leaks in application code
- Monitor connection usage patterns
ES004: TransactionError
Error: Transaction failed: serialization failure
Code: ES004
Cause: Database transaction could not be completed due to conflicts. Solution:
- Implement transaction retry logic
- Review transaction isolation levels
- Consider reducing transaction scope
ES005: MigrationError
Error: Migration error: Migration 20231201_001_create_events failed
Code: ES005
Cause: Database migration failed during startup. Solution:
- Check database permissions
- Verify migration scripts are valid
- Review database schema state
PostgreSQL-Specific Errors
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum PostgresError { #[error("Unique constraint violation: {constraint}")] UniqueConstraintViolation { constraint: String }, #[error("Foreign key constraint violation: {constraint}")] ForeignKeyViolation { constraint: String }, #[error("Check constraint violation: {constraint}")] CheckConstraintViolation { constraint: String }, #[error("Deadlock detected: {message}")] DeadlockDetected { message: String }, #[error("Query timeout: query exceeded {timeout:?}")] QueryTimeout { timeout: Duration }, #[error("Connection limit exceeded")] ConnectionLimitExceeded, } }
Projection Errors
ProjectionError
Errors from projection operations.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum ProjectionError { #[error("Projection not found: {name}")] NotFound { name: String }, #[error("Projection already exists: {name}")] AlreadyExists { name: String }, #[error("Event processing failed: {message}")] ProcessingFailed { message: String }, #[error("Checkpoint save failed: {message}")] CheckpointFailed { message: String }, #[error("Rebuild failed: {message}")] RebuildFailed { message: String }, #[error("Subscription error: {message}")] SubscriptionError { message: String }, #[error("State corruption detected: {message}")] StateCorruption { message: String }, #[error("Projection timeout: {projection} timed out after {duration:?}")] Timeout { projection: String, duration: Duration }, #[error("Configuration error: {message}")] ConfigurationError { message: String }, } }
Error Codes and Solutions
PR001: ProcessingFailed
Error: Event processing failed: Failed to apply UserCreated event
Code: PR001
Cause: Projection failed to process an event. Solution:
- Check projection logic for errors
- Verify event format matches expectations
- Implement proper error handling in projections
PR002: CheckpointFailed
Error: Checkpoint save failed: Database connection lost
Code: PR002
Cause: Unable to save projection checkpoint. Solution:
- Check database connectivity
- Verify checkpoint storage configuration
- Implement checkpoint retry logic
PR003: RebuildFailed
Error: Rebuild failed: Out of memory during rebuild
Code: PR003
Cause: Projection rebuild encountered an error. Solution:
- Increase memory allocation for rebuild operations
- Implement incremental rebuild strategies
- Check for memory leaks in projection code
PR004: StateCorruption
Error: State corruption detected: Checksum mismatch
Code: PR004
Cause: Projection state integrity check failed. Solution:
- Rebuild projection from beginning
- Investigate potential data corruption causes
- Verify checkpoint storage integrity
Validation Errors
ValidationError
Input validation errors from the nutype
validation system.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum ValidationError { #[error("Required field is empty: {field}")] Empty { field: String }, #[error("Value too long: {field} length {length} exceeds maximum {max}")] TooLong { field: String, length: usize, max: usize }, #[error("Value too short: {field} length {length} below minimum {min}")] TooShort { field: String, length: usize, min: usize }, #[error("Invalid format: {field} does not match expected format")] InvalidFormat { field: String }, #[error("Invalid range: {field} value {value} outside range [{min}, {max}]")] OutOfRange { field: String, value: String, min: String, max: String }, #[error("Predicate failed: {field} failed validation rule")] PredicateFailed { field: String }, #[error("Parse error: {field} could not be parsed - {message}")] ParseError { field: String, message: String }, } }
Error Codes and Solutions
VE001: Empty
Error: Required field is empty: stream_id
Code: VE001
Cause: Required field was empty or contained only whitespace. Solution:
- Ensure all required fields have values
- Check for null or empty string inputs
- Verify string trimming behavior
VE002: TooLong
Error: Value too long: stream_id length 300 exceeds maximum 255
Code: VE002
Cause: Input value exceeded maximum length constraint. Solution:
- Reduce input length to meet constraints
- Consider using shorter identifiers
- Review length requirements
VE003: InvalidFormat
Error: Invalid format: email does not match expected format
Code: VE003
Cause: Input value didn’t match expected format pattern. Solution:
- Verify input format matches requirements
- Check regular expression patterns
- Validate input on client side before submission
Configuration Errors
ConfigError
Configuration and setup errors.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum ConfigError { #[error("Missing required configuration: {key}")] MissingRequired { key: String }, #[error("Invalid configuration value: {key} = {value}")] InvalidValue { key: String, value: String }, #[error("Configuration file not found: {path}")] FileNotFound { path: String }, #[error("Configuration parse error: {message}")] ParseError { message: String }, #[error("Environment variable error: {message}")] EnvironmentError { message: String }, #[error("Validation error: {message}")] ValidationError { message: String }, } }
Error Codes and Solutions
CF001: MissingRequired
Error: Missing required configuration: DATABASE_URL
Code: CF001
Cause: Required configuration parameter not provided. Solution:
- Set missing environment variable or configuration value
- Check configuration file completeness
- Verify environment setup
CF002: InvalidValue
Error: Invalid configuration value: MAX_CONNECTIONS = -5
Code: CF002
Cause: Configuration value is invalid for the parameter type. Solution:
- Check value format and type requirements
- Verify numeric ranges and constraints
- Review configuration documentation
Network Errors
NetworkError
Network and connectivity related errors.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum NetworkError { #[error("Connection timeout: {endpoint}")] ConnectionTimeout { endpoint: String }, #[error("DNS resolution failed: {hostname}")] DnsResolutionFailed { hostname: String }, #[error("TLS error: {message}")] TlsError { message: String }, #[error("HTTP error: {status} - {message}")] HttpError { status: u16, message: String }, #[error("Network unreachable: {endpoint}")] NetworkUnreachable { endpoint: String }, #[error("Connection refused: {endpoint}")] ConnectionRefused { endpoint: String }, } }
Serialization Errors
SerializationError
Data serialization and deserialization errors.
#![allow(unused)] fn main() { #[derive(Debug, thiserror::Error)] pub enum SerializationError { #[error("JSON serialization failed: {message}")] JsonSerializationFailed { message: String }, #[error("JSON deserialization failed: {message}")] JsonDeserializationFailed { message: String }, #[error("Invalid JSON format: {message}")] InvalidJsonFormat { message: String }, #[error("Missing required field: {field}")] MissingField { field: String }, #[error("Unknown field: {field}")] UnknownField { field: String }, #[error("Type mismatch: expected {expected}, found {found}")] TypeMismatch { expected: String, found: String }, #[error("Schema version mismatch: expected {expected}, found {found}")] SchemaVersionMismatch { expected: String, found: String }, } }
Error Handling Patterns
Retry Strategies
EventCore provides different retry strategies for different error types:
#![allow(unused)] fn main() { // Automatic retry for transient errors match command_executor.execute(&command).await { Ok(result) => result, Err(CommandError::ConcurrencyConflict { .. }) => { // Retry with exponential backoff retry_with_backoff(|| command_executor.execute(&command)).await? }, Err(CommandError::Timeout { .. }) => { // Retry with different timeout command_executor.execute_with_timeout(&command, increased_timeout).await? }, Err(other) => return Err(other), // Don't retry business logic errors } }
Error Conversion
Common error conversion patterns:
#![allow(unused)] fn main() { // Convert EventStore errors to Command errors impl From<EventStoreError> for CommandError { fn from(err: EventStoreError) -> Self { match err { EventStoreError::VersionConflict { .. } => { CommandError::ConcurrencyConflict { streams: vec![] } }, EventStoreError::StreamNotFound { stream_id } => { CommandError::StreamNotFound { stream_id } }, other => CommandError::EventStoreError { source: other }, } } } }
Error Context
Adding context to errors for better debugging:
#![allow(unused)] fn main() { use anyhow::{Context, Result}; async fn execute_command<C: Command>(command: &C) -> Result<ExecutionResult> { command_executor .execute(command) .await .with_context(|| format!("Failed to execute command: {}", std::any::type_name::<C>())) .with_context(|| "Command execution failed in main handler") } }
Troubleshooting Guide
Quick Reference
Performance Issues:
- Check
CE006: Timeout
errors → Review system performance - Check
ES003: ConnectionPoolExhausted
→ Increase pool size or fix leaks - Check
PR003: RebuildFailed
→ Optimize memory usage
Data Issues:
- Check
CE003: ConcurrencyConflict
→ Implement retry logic - Check
ES001: VersionConflict
→ Review optimistic concurrency - Check
PR004: StateCorruption
→ Rebuild projections
Configuration Issues:
- Check
CF001: MissingRequired
→ Set required configuration - Check
ES002: ConnectionFailed
→ Verify database connectivity - Check
CF002: InvalidValue
→ Review configuration values
Security Issues:
- Check
CE005: Unauthorized
→ Verify permissions - Check
CE007: StreamAccessDenied
→ Fix stream access patterns
Diagnostic Commands
# Check EventCore health
eventcore-cli health-check
# Validate configuration
eventcore-cli config validate
# Test database connectivity
eventcore-cli database ping
# Check projection status
eventcore-cli projections status
# Verify stream access
eventcore-cli commands validate <command-type>
Log Analysis
Common log patterns to look for:
# High error rates
grep "ERROR" logs/eventcore.log | grep -c "CommandError"
# Concurrency conflicts
grep "ConcurrencyConflict" logs/eventcore.log | tail -10
# Performance issues
grep "Timeout\|slow query" logs/eventcore.log
# Connection issues
grep "ConnectionFailed\|ConnectionPoolExhausted" logs/eventcore.log
Error Prevention
Best Practices
- Input Validation: Use type-safe domain types with validation
- Error Handling: Implement comprehensive error handling strategies
- Monitoring: Set up alerts for error rate thresholds
- Testing: Include error scenarios in integration tests
- Documentation: Document expected error conditions
Type Safety
EventCore’s type system prevents many error categories:
#![allow(unused)] fn main() { // Good: Type-safe stream access #[derive(Command)] struct TransferMoney { #[stream] source_account: StreamId, // Guaranteed valid #[stream] target_account: StreamId, // Guaranteed valid amount: Money, // Guaranteed valid currency/amount } // Prevents: CE007 StreamAccessDenied, VE001-VE003 validation errors }
This completes the error reference documentation. Use this guide to understand, diagnose, and resolve EventCore errors effectively.
Next, explore the Glossary →