Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Zig Dictionary
  3. Error Set Type

Error Set Type

In Zig, error values are explicitly defined as error set types. Writing error{Foo, Bar} declares a set of error values as a type, and by combining it with !T (an error union) as a function's return type, you can handle "success returns T, failure returns an error value" in a type-safe way. Error set types have a structure similar to enums, but they also support merging multiple sets with || and accepting them as anyerror (a superset of all errors), making them flexible to use.

Syntax

// -----------------------------------------------
// Defining an error set type
// -----------------------------------------------

// Use error{value1, value2, ...} to define an error set type
const MyError = error{
    NotFound,       // Error values start with an uppercase letter
    InvalidInput,
    Overflow,
};

// -----------------------------------------------
// Functions with an error union type  !T
// -----------------------------------------------

// The return type !T means "either T or one of MyError"
fn functionName(arg: Type) MyError!T {
    if (condition) return error.InvalidInput;  // Return an error with error.valueName
    return normalValue;
}

// Inferred error set (!T) — the compiler infers the error set
fn functionName2(arg: Type) !T {
    // ...
}

// -----------------------------------------------
// Handling an error union
// -----------------------------------------------

// try — propagates the error to the caller if one occurs (most common pattern)
const value = try functionName(arg);

// catch — catches the error and returns a fallback value
const value2 = functionName(arg) catch defaultValue;

// catch |err| — receives the error variable and handles it
const value3 = functionName(arg) catch |err| blk: {
    std.debug.print("Error: {}\n", .{err});
    break :blk defaultValue;
};

// Use switch to branch on the error
const result = functionName(arg) catch |err| switch (err) {
    error.NotFound    => defaultValueA,
    error.InvalidInput => defaultValueB,
    else              => return err,  // Re-propagate unexpected errors
};

// -----------------------------------------------
// Merging error sets (|| operator)
// -----------------------------------------------

const CombinedError = ErrorSetA || ErrorSetB;  // Merges both sets

// -----------------------------------------------
// anyerror — a superset of all error values
// -----------------------------------------------

fn genericFunction(arg: Type) anyerror!T { ... }

Error set operations summary

Syntax / TypeDescription
error{A, B}Defines an error set type inline. Creates a type that groups multiple error values.
const E = error{A, B};Gives the error set type a name so it can be reused.
error.AProduces an error value. Can be returned from a function as an error set type value.
E!TAn error union type. Represents "either T or one of the errors in set E".
!TAn inferred error union type. The compiler automatically infers the error set.
try exprPropagates the error to the caller if the expression fails, or returns the unwrapped value on success.
expr catch valUses val as a fallback when an error occurs.
expr catch |err| { ... }Receives the error variable err and handles it in a block.
A || BMerges two error set types into a new error set type.
anyerrorA superset type that includes all error values. Used in generic functions and interfaces.
@errorName(err)Converts an error value to a string slice ([]const u8).
@typeInfo(E).ErrorSetRetrieves metadata about an error set type (such as the list of values) at compile time.

Sample code

evangelion_error_set.zig
// evangelion_error_set.zig — sample code for error set types
// Uses Evangelion characters to demonstrate
// error{} definitions, error unions, try/catch, and || merging

const std = @import("std");

// -----------------------------------------------
// Defining error set types
// -----------------------------------------------

// Errors that can occur at the NERV command center
const NervError = error{
    PilotNotFound,      // No pilot was found
    SyncRatioTooLow,    // Sync ratio is below the required threshold
    ATFieldFailure,     // AT Field deployment failed
};

// Errors that can occur during the Eva activation sequence (defined as a separate set)
const ActivationError = error{
    CoreLockout,        // Access to the core is locked
    PowerSupplyLost,    // Power supply was cut off
};

// Merge the two error sets with || (represents errors for the entire launch sequence)
const LaunchError = NervError || ActivationError;

// -----------------------------------------------
// Functions that return an error union
// -----------------------------------------------

// Validates a pilot's sync ratio (returns an error if too low)
fn validateSyncRatio(pilot_name: []const u8, ratio: f32) NervError!f32 {
    if (ratio < 40.0) {
        std.debug.print(
            "  [{s}] Sync ratio {d:.1}% — below threshold, returning error\n",
            .{ pilot_name, ratio },
        );
        return error.SyncRatioTooLow;
    }
    std.debug.print(
        "  [{s}] Sync ratio {d:.1}% — OK\n",
        .{ pilot_name, ratio },
    );
    return ratio;
}

// Seats a pilot in the entry plug (returns NotFound if the name is empty)
fn seatPilot(pilot_name: []const u8) NervError![]const u8 {
    if (pilot_name.len == 0) return error.PilotNotFound;
    std.debug.print("  [{s}] Entry plug loaded\n", .{pilot_name});
    return pilot_name;
}

// Runs a pre-launch check combining both functions above
// NervError!void — returns void on success (no value)
fn prelaunchCheck(pilot_name: []const u8, ratio: f32) NervError!void {
    _ = try seatPilot(pilot_name);          // Propagates the error to the caller if one occurs
    _ = try validateSyncRatio(pilot_name, ratio);
    std.debug.print("  [{s}] Pre-launch check complete\n", .{pilot_name});
}

// -----------------------------------------------
// Error handling patterns using catch
// -----------------------------------------------

// Returns the sync ratio, or 0.0 as a default on error
fn getSyncRatioOrDefault(pilot_name: []const u8, ratio: f32) f32 {
    return validateSyncRatio(pilot_name, ratio) catch 0.0;
}

// Returns the sync ratio, logging the error before returning the default
fn getSyncRatioWithLog(pilot_name: []const u8, ratio: f32) f32 {
    return validateSyncRatio(pilot_name, ratio) catch |err| blk: {
        // Convert the error value to a string with @errorName
        std.debug.print(
            "  Caught error: {s}\n",
            .{@errorName(err)},
        );
        break :blk -1.0;
    };
}

// -----------------------------------------------
// Branching on errors with switch
// -----------------------------------------------

// Returns a response message for each NervError using switch
fn handleNervError(err: NervError) []const u8 {
    return switch (err) {
        error.PilotNotFound   => "Pilot unknown — requesting emergency dispatch",
        error.SyncRatioTooLow => "Sync ratio too low — switching to forced connection mode",
        error.ATFieldFailure  => "AT Field failure — deploying N2 mine as countermeasure",
    };
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    try stdout.print("=== NERV Third Tokyo City Operations Command Center ===\n\n", .{});

    // -----------------------------------------------
    // Propagation with try and the success case
    // -----------------------------------------------

    try stdout.print("--- Pre-launch check (success case) ---\n", .{});

    // Shinji Ikari (Unit-01 pilot) — sync ratio is high enough, completes normally
    prelaunchCheck("Shinji Ikari", 88.5) catch |err| {
        try stdout.print("  Launch failed: {s}\n", .{handleNervError(err)});
    };

    try stdout.print("\n--- Pre-launch check (sync ratio too low) ---\n", .{});

    // Kaworu Nagisa — sync ratio is too low, results in an error
    prelaunchCheck("Kaworu Nagisa", 12.0) catch |err| {
        try stdout.print("  Launch failed: {s}\n", .{handleNervError(err)});
    };

    try stdout.print("\n--- Pre-launch check (pilot unknown) ---\n", .{});

    // Empty name — results in PilotNotFound error
    prelaunchCheck("", 75.0) catch |err| {
        try stdout.print("  Launch failed: {s}\n", .{handleNervError(err)});
    };

    // -----------------------------------------------
    // Getting a default value with catch
    // -----------------------------------------------

    try stdout.print("\n--- Getting a default value with catch ---\n", .{});

    // Rei Ayanami — sync ratio is too low, so the default value 0.0 is returned
    const rei_ratio = getSyncRatioOrDefault("Rei Ayanami", 30.0);
    try stdout.print("  Rei Ayanami sync ratio (adjusted): {d:.1}%\n", .{rei_ratio});

    // Asuka Langley Soryu — high enough, so the actual value is returned
    const asuka_ratio = getSyncRatioOrDefault("Asuka Langley Soryu", 95.3);
    try stdout.print("  Asuka sync ratio: {d:.1}%\n", .{asuka_ratio});

    // -----------------------------------------------
    // Logging an error with catch |err|
    // -----------------------------------------------

    try stdout.print("\n--- Logging an error with catch |err| ---\n", .{});

    const rei_ratio2 = getSyncRatioWithLog("Rei Ayanami", 22.0);
    try stdout.print("  Result: {d:.1}\n", .{rei_ratio2});

    // -----------------------------------------------
    // Merging error sets (LaunchError = NervError || ActivationError)
    // -----------------------------------------------

    try stdout.print("\n--- Merging error sets (LaunchError) ---\n", .{});

    // LaunchError holds values from both NervError and ActivationError
    const launch_errors = [_]LaunchError{
        error.PilotNotFound,
        error.SyncRatioTooLow,
        error.ATFieldFailure,
        error.CoreLockout,
        error.PowerSupplyLost,
    };

    for (launch_errors) |err| {
        // Stringify the error value with @errorName
        try stdout.print("  {s}\n", .{@errorName(err)});
    }
}
zig run evangelion_error_set.zig
=== NERV Third Tokyo City Operations Command Center ===

--- Pre-launch check (success case) ---
  [Shinji Ikari] Entry plug loaded
  [Shinji Ikari] Sync ratio 88.5% — OK
  [Shinji Ikari] Pre-launch check complete

--- Pre-launch check (sync ratio too low) ---
  [Kaworu Nagisa] Entry plug loaded
  [Kaworu Nagisa] Sync ratio 12.0% — below threshold, returning error
  Launch failed: Sync ratio too low — switching to forced connection mode

--- Pre-launch check (pilot unknown) ---
  Launch failed: Pilot unknown — requesting emergency dispatch

--- Getting a default value with catch ---
  [Rei Ayanami] Sync ratio 30.0% — below threshold, returning error
  Rei Ayanami sync ratio (adjusted): 0.0%
  [Asuka Langley Soryu] Sync ratio 95.3% — OK
  Asuka sync ratio: 95.3%

--- Logging an error with catch |err| ---
  [Rei Ayanami] Sync ratio 22.0% — below threshold, returning error
  Caught error: SyncRatioTooLow
  Result: -1.0

--- Merging error sets (LaunchError) ---
  PilotNotFound
  SyncRatioTooLow
  ATFieldFailure
  CoreLockout
  PowerSupplyLost

Overview

Zig's error set type makes it possible to detect missing error handling and unexpected error values at compile time by explicitly expressing "which errors can occur" as a type. You define the set with error{...} and combine it with !T (an error union) to make a function's failure modes readable directly from its signature. try is the most concise way to propagate an error upward, while catch is used when you want to handle it inline. Merging error sets with || is useful for combining errors from multiple subsystems into a single type. anyerror is a highly versatile superset of all error values, but because the compiler cannot perform exhaustiveness checks on it, using a concrete error set type is recommended when possible. For converting error values to strings with @errorName and for guidance on when to use optional types instead, see optional (optional type).

If you find any errors or copyright issues, please .