Error Handling & Exceptions
Relevant source files
The following files were used as context for generating this wiki page:
Error handling in flext-cli is built upon a dual-layer strategy: a traditional exception hierarchy for catastrophic or unexpected failures, and a functional "Railway" pattern for controlled, logic-driven error states. This approach ensures that developers can distinguish between systemic failures (exceptions) and expected domain failures (results), such as validation errors or missing files.
The architecture prioritizes typed error returns over side-effect-heavy try-except blocks, particularly when dealing with I/O operations, Pydantic model validations, and user prompts. This is enforced through the project's Engineering Law, which mandates parsing untrusted input into canonical types and fixing root causes rather than using silent suppressions.
Sources: AGENTS.md:65-67, examples/README.md:12-15
The Railway Pattern (p.Result)
The primary mechanism for handling fallible operations is the p.Result container, often abbreviated as r in implementation code. This pattern, referred to as the "Railway Pattern," allows functions to return either a successful value or an error message without raising an exception.
Result Flow Architecture
When a function executes, it returns a Result object. Subsequent logic is chained using .map() for success transformations or .flat_map() for operations that also return a Result. If any step fails, the error "bypasses" the rest of the success chain.
This diagram illustrates the "Railway" flow where errors branch off the main success track immediately.
Sources: examples/ex_12_pydantic_driven_cli.py:53-84, examples/ex_11_complete_integration.py:65-74
Implementation Example
In ex_11_complete_integration.py, data loading utilizes this pattern to handle missing files and type mismatches gracefully:
def load_data(self) -> p.Result[t.JsonMapping]:
if not self.data_file.exists():
return r[t.JsonMapping].fail(_EXAMPLE_ERR_NO_DATA_FILE_FOUND)
read_result = cli.read_json_file(str(self.data_file))
if read_result.failure:
return r[t.JsonMapping].fail(read_result.error or "Unknown error")
# ... logic continues ...
Sources: examples/ex_11_complete_integration.py:65-71
Exception Hierarchy
While the Railway pattern handles business logic, flext-cli uses a standard exception hierarchy for structural and validation failures, particularly when integrating with Pydantic.
| Exception Class | Description |
|---|---|
ValidationError | Raised when Pydantic models fail to validate input against defined schemas. |
csv.Error | Raised during failures in CSV string parsing. |
ValueError | Used for business rule violations, such as invalid hostnames or log levels. |
Sources: examples/ex_12_pydantic_driven_cli.py:108-112, src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_04.py:106-110, tests/unit/test_examples_models_utilities_cov.py:68-80
Standard Error Constants
The project centralizes specific error strings to maintain consistency across the CLI and its utilities.
| Constant Category | Typical Messages / Usage |
|---|---|
| File Operations | No data file found, Unsupported format, Auto-load failed |
| Validation | Missing required fields, Invalid host, Data must be mapping |
| User Interaction | Prompt failed |
Sources: examples/ex_11_complete_integration.py:44-45, src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_04.py:34-40, examples/ex_12_pydantic_driven_cli.py:98-100
Validation Logic and Guards
Error handling is deeply integrated into the data validation lifecycle. Filesystem helpers and model converters use specific guards to ensure data integrity before processing.
I/O Guard Patterns
Filesystem utilities implement specific checks to prevent common I/O errors from bubbling up as unhandled exceptions.
This flow represents the logic used in directory removal and copy operations.
Sources: src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_04.py:141-150
Pydantic Validation Chaining
In complex CLI workflows, validation is applied in layers:
- Required Field Check: Ensures all keys exist in raw input.
- Pydantic Transformation: Validates types and constraints.
- Business Rule Application: Checks cross-field logic (e.g., specific ports for SSL).
- Connection Testing: Final runtime validation.
Sources: examples/ex_12_pydantic_driven_cli.py:53-84, examples/ex_12_pydantic_driven_cli.py:126-135
Conclusion
The error handling system in flext-cli is designed to be "loud" and explicit. By combining functional Result objects for expected logic paths with a strict validation hierarchy, the project ensures that failures are caught early and reported with high-fidelity error messages rather than generic stack traces. This architecture supports the project's goal of providing a professional, resilient developer CLI experience.
Sources: AGENTS.md:273-277, examples/README.md:52-54