The Result Pattern & Error Handling
Relevant source files
The following files were used as context for generating this wiki page:
The FLEXT Plugin system implements the Result Pattern (often referred to as the r pattern) as its primary mechanism for error handling and data flow control. This architectural choice facilitates Railway-Oriented Programming (ROP), ensuring that errors are treated as first-class citizens rather than exceptional control flow breaks. By wrapping return values in a standardized Result object, the system enables safe functional composition and explicit error propagation throughout the plugin lifecycle.
Sources: examples/README.md:213-222, src/flext_plugin/_utilities/plugin_platform.py:165-175
Core Result Architecture
The Result pattern centers on a containerized return type, typically denoted as p.Result[T] or r[T]. This container explicitly signals whether an operation succeeded or failed, carrying either the successful payload or a descriptive error message.
Result Structure and Types
The system uses r[T].ok(value) to represent successful outcomes and r[T].fail(error_message) for failures. This approach replaces standard Python try-except blocks in many business logic layers, though try-except is still used internally within methods to catch and wrap exceptions into Result objects.
| Method | Return Type | Purpose |
|---|---|---|
ok(data/value) | p.Result[T] | Returns a success state with the associated data. |
fail(message) | p.Result[T] | Returns a failure state with an error string. |
success() | bool | Property or method to check if the result is successful. |
failure() | bool | Property or method to check if the result failed. |
value | T | The payload of a successful result. |
error | str | The error message of a failed result. |
Sources: examples/basic-plugin.md:23-45, src/flext_plugin/_utilities/plugin_platform.py:343-348
Functional Composition (Railway-Oriented)
The PluginPlatformService utilizes functional composition methods like flat_map and map to chain operations. If any step in the chain returns a failure Result, subsequent steps are bypassed, and the error propagates to the end of the chain.
This diagram illustrates how the Result pattern enables "Railway-Oriented Programming" where failures shunt the execution to a parallel "error track".
Sources: src/flext_plugin/_utilities/plugin_platform.py:270-285, src/flext_plugin/_utilities/plugin_platform.py:302-315
Error Handling in Plugin Lifecycle
The lifecycle methods (initialize, execute, cleanup) of a FlextPlugin are strictly typed to return p.Result. This ensures that the plugin platform can safely orchestrate plugins without risking unhandled crashes.
1. Initialization and Validation
During initialize(), plugins validate their configuration. If validation fails, an error Result is returned, preventing the plugin from moving to an ACTIVE status.
def initialize(self) -> p.Result[bool]:
try:
# Validate configuration
validation_result = self._validate_configuration()
if validation_result.failure():
return validation_result
# Setup resources...
return r[bool].ok(data=True)
except Exception as e:
return r[bool].fail(f"Initialization failed: {e}")
Sources: examples/basic-plugin.md:83-108, src/flext_plugin/models.py:168-185
2. Execution Flow
The execute() method validates both the internal state of the plugin (e.g., initialized and active) and the input data before processing. Errors at any validation point return immediately.
Sequence of internal checks during plugin execution ensuring safety through Result returns.
Sources: examples/basic-plugin.md:110-143, src/flext_plugin/_utilities/plugin_platform.py:328-356
Error Recording and Metadata
FLEXT Plugins automatically track their error history within the Plugin.Entity model. This allows for persistent monitoring of plugin health.
Metadata Error Tracking
The Plugin.Entity provides methods to record errors and execution metrics into a metadata dictionary:
record_error(message): Incrementserror_countand updateslast_error.record_execution(time, success): Tracksexecution_count,total_execution_time,success_count, andfailure_count.
| Field | Type | Description |
|---|---|---|
error_count | int | Total number of recorded failures. |
last_error | str | The last error message encountered. |
success_count | int | Total successful executions. |
failure_count | int | Total failed executions. |
Sources: src/flext_plugin/models.py:113-166, tests/unit/test_domain_entities.py:82-108
Validation Rules
Error handling is also enforced through business rule validation using validate_business_rules(). This method checks for structural integrity before registration.
def validate_business_rules(self) -> p.Result[bool]:
if not self.name or not self.name.strip():
return r[bool].fail("Plugin name cannot be empty")
version_parts = self.plugin_version.split(".")
if len(version_parts) < 2 or len(version_parts) > 3:
return r[bool].fail(f"Invalid semantic version: {self.plugin_version}")
return r[bool].ok(value=True)
Sources: src/flext_plugin/models.py:168-192, examples/03_docker_integration.py:160-165
Summary
The Result Pattern and Error Handling in FLEXT provide a robust, type-safe framework for plugin development. By standardizing on p.Result, the system eliminates the ambiguity of return values, enforces state validation throughout the lifecycle, and enables detailed telemetry through error recording in entity metadata. This functional approach ensures that both the platform and individual plugins remain resilient and easy to debug.