Trying to achieve this process when the user encounters errors: 🤬 -> 🤔 -> 😮 -> 🤩. Studying the best approaches to classifying errors
This project was organized in 3 parts:
- Concepts
- Strategies to error handling (checkout the handling-errors repository)
- Error messages categorization
Note
This project is part of a series of studies about error handling and classification. Check out the other projects:
Error handling is a critical part of software development, but programmers often approach it in an ad-hoc manner. Since human error is unavoidable, and errors can occur whenever people or external systems are involved, it's essential to handle them thoughtfully. Effective error handling is as important as the core business logic, ensuring your software continues to function despite unexpected issues.
-
Exceptional Errors: These are unexpected but possible events. You safeguard against them even if they rarely occur. Examples include:
- Running out of memory
- Invalid JSON format
- Missing database object
Exceptional errors should be handled gracefully but are rare enough that frequent occurrence would indicate a design flaw. If errors are expected regularly, they aren't truly exceptional.
-
Failures: Failures occur when an operation cannot proceed, and they happen more predictably. Examples include:
- Incorrect passwords
- CDN downtime
- Missing device permissions
- No network connection
Failures are handled in various ways, such as with error codes, strings, or conditional logic, depending on the situation.
-
Internal Errors: These are caused by flaws in the system's design or logic. Examples include:
- Incorrect use of operators
- Misconstructed regular expressions
- Poorly written tests
Internal errors should be prevented, not handled at runtime. Unit tests help catch these, and error handling for internal issues should be minimal because the focus should be on prevention.
-
External Errors: These originate from outside the system, such as from users, third-party services, or dependencies. External errors are inevitable and should be handled with more complexity, as you cannot prevent them. Integration tests are suited for these errors since they involve interactions with the external environment.
-
Internal Errors: Easier to prevent but harder to handle. Unit testing and validation are key.
-
External Errors: Easier to handle but harder to prevent. These require robust error-handling strategies.
Effective error messaging must be precise and helpful, especially when errors affect the user. The precision of error messages can vary:
- General: "These credentials are invalid."
- Specific: "The password is incorrect."
- Detailed: "The given password is two characters off from the expected password."
The goal is to provide users with enough information to understand what went wrong and how to fix it.
The usefulness of error data depends on how it's gathered and used. For failures, error messages must provide enough context for the user to recover from the error. In the case of exceptional errors, messages should enable system recovery, and the error handling strategy should be flexible depending on the programming environment.
Every error should have a well-structured class, error code, and name. Key data fields include:
- Which operation failed
- Invalid inputs
- Input values
- Timestamps
- User-readable messages
Logging error data immediately is important, but only necessary information should be passed back to the user.
Error handling must strike a balance between simplicity and necessary complexity:
- Simple Approach: Boolean values or basic error codes that signal the occurrence of an error.
- Complex Approach: Defining classes for every error, which can add unnecessary overhead.
Error handling should be complex enough to support error recovery and analytics without overburdening the system.
Errors should be logged as soon as they are detected. Recovery strategies include either fixing the issue (like auto-correcting or showing a user-friendly error message) or passing the error along. For instance:
- Internal Error: Inform the user about a failure beyond their control and work on future prevention (e.g., bug reporting).
- External Error: Guide the user on how to resolve the issue or suggest that the problem is outside their influence.
Automatically handled, such as a connection timeout with an auto-reconnect feature.
Errors that can be corrected without user involvement but should still inform the user of the action taken. Example: An out-of-stock item is removed from a cart.
Errors that can be avoided through design improvements. Examples include:
- Disabling buttons in insufficient wallet balance scenarios.
- Providing password setup instructions to prevent validation issues.
These are inevitable but can be resolved by providing clear, user-friendly error messages. Avoid ambiguous error codes that require users to consult external resources.
For errors that cannot be fixed by the user, error reporting tools should be integrated to allow developers to address them efficiently.
Critical UX failures, such as app crashes or blank screens, that abruptly terminate the user experience.
- Make errors easy to discover and map them to where they occur.
- Prevent errors wherever possible.
- Keep error messages short, clear, and free of jargon.
- Avoid blaming the user and focus on offering clear steps for resolution.
- Use real-time validation and system helpers like autocomplete.
- Automatically fix errors when possible.
- Group and sequence data logically.
- Explain unfamiliar concepts clearly.
Exceptions should only be used for exceptional situations, not for normal flow control, as this complicates the code and makes it harder to manage. Instead, handle known errors explicitly and reserve exceptions for cases where recovery is impossible or unknown.
Prevent internal errors; handle external errors. Keep error handling as simple as possible but complex enough for effective recovery and analysis. Always prioritize user-friendly error messages and recovery paths.
- Clone this repository
git clone https://github.com/pferreirafabricio/classify-error-messages.git
- Enter in the project's folder:
cd classify-error-messages
- Enter in the API's project:
cd ClassifyErrorMessages
- Run the API:
dotnet watch run
- Finally open the Swagger client:
http://localhost:5003/swagger/index.html
- The Error Handbook, Part 1 – Two Ways to Categorize Errors
- The Error Handbook, Part 2 – How to Shape and Represent Your Error Data
- The Error Handbook, Part 3 – How to Handle Your Errors
- Categorising Errors-and how to handle them
- Railway oriented programming - A recipe for a functional app, part 2
- Functional Error Handling in .NET With the Result Pattern
- Problem Details for HTTP APIs - RFC 7807
- Best practices for reporting bugs in web projects (and much more)