Welcome. In this course, you will learn how Elixir handles errors and builds fault-tolerant systems. Since this is our first unit, we will start with exceptions and how to convert them into predictable return values using try/rescue. This pattern is useful when you want to keep a function pure and return {:ok, value} or {:error, reason} instead of crashing.
What it does:
- The
tryblock attemptsa / b. - If
bis0, Elixir raises anArithmeticError, which we rescue and convert to{:error, "Cannot divide by zero"}. - The second
rescueclause matches any other exception, binds it toe, and returns a friendly error string. This keeps the function’s contract stable: always return{:ok, value}or{:error, reason}.
Why it matters:
- In production, a simple math mistake should not bring down your process. Converting exceptions to tagged tuples makes failures explicit and easy to handle with pattern matching.
Note: rescue matches exceptions; catch is for low-level Erlang “throws” and is rarely needed in day-to-day Elixir. For example, you might see throw/catch used for non-local returns in legacy code, but idiomatic Elixir almost always prefers exceptions and rescue. Prefer rescuing specific exception types when possible.
What it does:
String.to_integer/1raisesArgumentErroron bad input (like"abc"). We rescue that and return{:error, "Invalid integer format"}.IO.inspectshows the outcomes:ErrorHandler.safe_divide(10, 2)->{:ok, 5.0}ErrorHandler.safe_divide(10, 0)->{:error, "Cannot divide by zero"}ErrorHandler.parse_integer("42")->{:ok, 42}ErrorHandler.parse_integer("abc")->{:error, "Invalid integer format"}
Design takeaway:
- This approach gives you a clean, uniform interface. Callers can pattern match on
{:ok, value}or{:error, reason}without worrying about exceptions leaking out.
Note: Exceptions are relatively “heavy.” Use try/rescue when interacting with code that raises (like parsing or I/O). For ordinary control flow, prefer returning {:ok, ...} | {:error, ...} directly. In production OTP systems, it’s often better to “let it crash” and rely on supervisors to restart failed processes, rather than catching every exception. In later units, you will see how supervisors help you “let it crash” safely when that’s the better choice.
You learned how to:
- Use
try/rescueto catch exceptions and return stable tuples within a module. - Rescue specific exception types (
ArithmeticError,ArgumentError) and provide clear error messages. - Keep your public API predictable by avoiding raised exceptions at call sites.
- Prefer “let it crash” with supervision for many real-world errors, using
try/rescuemainly for boundary cases or when interacting with code that raises.
You are ready to practice transforming exceptions into friendly results and inspecting them. The next step will be hands-on — let’s put this pattern to work and build your confidence.
