# Error Handling

Did you see the `!void`return type of the `main`function from earlier? That is Zig's way of indicating that the `main`function could possibly return an error. Error handling is a feature that was designed carefully in Zig, and worth exploring before we go further.

## Defining an error

An error is defined in a similar way to an enum. You can also use `||`to combine different error types together. Here are some errors from the standard library.

```zig
// in std/mem/Allocator.zig
pub const Error = error{
    OutOfMemory,
};

// in std/io.zig
pub const NoEofError = ReadError || error{
    EndOfStream,
};

// in std/dynamic_library.zig
const ElfDynLibError = error{
    FileTooBig,
    NotElfFile,
    NotDynamicLibrary,
    MissingDynamicLinkingInformation,
    ElfStringSectionNotFound,
    ElfSymSectionNotFound,
    ElfHashTableNotFound,
} || posix.OpenError || posix.MMapError;
```

## Returning errors

After defining your error, you have to indicate that a function you've written can possibly return an error. This is done by placing the error name, then a `!`, then the actual return type.

In the following example, the function `myFunction`can *only* return `MyError`. There is no other possible error type. On the other hand, `myOtherFunction`could possibly return other error types — its error type is *inferred* from the function body.

```zig
const MyError = error{
    FooReason,
    BarReason,
    AnotherReason,
};

pub fn myFunction(x: i32) MyError!i32 {
    if (x < 43) {
        // Simply return the error if you encounter an error condition, instead
        // of returning the result.
        return MyError.FooReason;
    } else if (x > 43) {
        return MyError.BarReason;
    } else {
        return 33;
    }
}

// Here the error type is inferred, instead of being explicitly defined.
pub fn myOtherFunction(x: i32) !i32 {
    if (x < 99) {
        return MyError.AnotherReason;
    } else if (x > 99) {
        return MyError.BarReason;
    } else {
        return 22;
    }
}
```

{% hint style="info" %}
Zig also has an `anyerror`type, which represents the union of all the error types across the entire program. So pretty much *any error in the program*.
{% endhint %}

## Handling errors

You can either use `try`to propagate errors from functions that you call, or `catch`to handle the errors at the call site. In Zig, errors *must* be handled (eventually), otherwise you'll get a compiler **error**.

```zig
pub fn main() !void {
    // This will propagate the error up to the caller of this function.
    // In the case of the `main` function, it would end the program.
    const my_function_result = try myFunction(43);
    std.debug.print("The result of myFunction is: {}\n", .{my_function_result});

    // Instead of propagating the error, you can also handle it.
    const my_other_function_result = myOtherFunction(43) catch |err| {
        switch (err) {
            MyError.FooReason => std.debug.print("FooReason\n", .{}),
            MyError.BarReason => std.debug.print("BarReason\n", .{}),
            MyError.AnotherReason => std.debug.print("AnotherReason\n", .{}),
        }
        // Return early from the main function.
        return;
    };
    std.debug.print("The result of myOtherFunction is: {}\n", .{my_other_function_result});
}
```
