> ## Documentation Index
> Fetch the complete documentation index at: https://docs.astrakairo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling in Kairo: Result and Faults Explained

> Handle expected business failures with Result<T, E> and understand how faults differ from ordinary errors in Kairo — no try/catch syntax in v0.1.

Kairo draws a hard line between two different kinds of bad outcome. A **failure** is an expected, domain-meaningful result — validation rejects an input, a payment is declined, a record is not found. A **fault** is an unexpected invariant violation — something your program assumed could not happen, did happen. `Result<T, E>` is the tool for failures: it is a first-class value that your functions return and your callers handle explicitly. Faults are not `Result` values; they terminate the current execution boundary and signal that the program reached a state it was not designed to handle. Keeping these two categories separate means your domain logic stays clean, your error paths are visible, and unexpected failures never silently masquerade as normal outcomes.

## `Result<T, E>` — Construction

`Result<T, E>` is part of the Core prelude. You do not need to import it. Construct a successful outcome with `Result.success()` and a failed outcome with `Result.failure()`.

```kairo theme={null}
public func divide(a: Decimal, b: Decimal): Result<Decimal, MathError> {
    if b == 0 {
        return Result.failure(MathError.DivisionByZero)
    }
    return Result.success(a / b)
}
```

The type parameter `E` must be value-like — use an `enum` or a `value` type, not a raw `Text` or a numeric code. This ensures errors are structured, pattern-matchable, and self-documenting.

```kairo theme={null}
public enum MathError {
    DivisionByZero
    Overflow
}
```

## Inspecting a `Result`

A `Result<T, E>` exposes four members for inspection:

| Member       | Type   | Description                                               |
| ------------ | ------ | --------------------------------------------------------- |
| `.isSuccess` | `Bool` | `true` if the outcome is a success                        |
| `.isFailure` | `Bool` | `true` if the outcome is a failure                        |
| `.value`     | `T`    | The success value — only safe to access when `.isSuccess` |
| `.error`     | `E`    | The error value — only safe to access when `.isFailure`   |

<Warning>
  Accessing `.value` on a failed `Result`, or `.error` on a successful `Result`, causes a **fault** — an unexpected runtime error that terminates the current execution boundary. Always guard access with `.isSuccess` or `.isFailure` first.
</Warning>

## Canonical Inspection with `match`

The standard way to handle a `Result` is to `match` on its `.isSuccess` property. This makes both branches visible and forces you to handle each case explicitly.

```kairo theme={null}
let outcome = divide(a: total, b: count)

match outcome.isSuccess {
    true {
        let average = outcome.value
        Pulse.Console.out.writeLine("Average: " + average.toString())
    }
    false {
        let err = outcome.error
        Pulse.Console.out.writeLine("Error: " + err.toString())
    }
}
```

You can also use `if` when only one branch needs action:

```kairo theme={null}
if outcome.isFailure {
    return Result.failure(outcome.error)
}

let average = outcome.value
```

<Tip>
  Propagating a failure up the call stack is idiomatic in Kairo. If your function cannot recover from an inner failure, return `Result.failure(...)` immediately and let the caller decide what to do.
</Tip>

## Designing Error Types

Error types communicate the full vocabulary of ways an operation can fail. Prefer `enum` when the set of failure cases is closed and each case is self-contained:

```kairo theme={null}
public enum ValidationError {
    EmptyName
    NameTooLong
    InvalidCharacters
}
```

Use a `value` type when a failure case carries structured data that the caller needs to act on:

```kairo theme={null}
public value InsufficientFundsError {
    available: Money
    required: Money
}
```

You can also combine the two — a `value` that wraps an `enum` code together with relevant identifiers:

```kairo theme={null}
public value CustomerLookupFailure {
    code: CustomerLookupFailureCode
    customerId: CustomerId
}
```

<Warning>
  Do not use raw `Text` or numeric codes as error types. `Result.failure("something went wrong")` is not meaningful to a caller. A typed error — `ValidationError.NameTooLong` — is pattern-matchable, documentable, and refactorable.
</Warning>

## Faults

A **fault** is distinct from a `Result` failure. Where a failure is an expected outcome that your function deliberately returns, a fault is an unexpected invariant violation that Kairo detects at runtime and treats as an unrecoverable condition within the current execution boundary.

Faults occur when your code does something it should never have done — for example:

* Accessing `.value` on a failed `Result`
* Accessing `.error` on a successful `Result`
* Violating a precondition the runtime enforces

```kairo theme={null}
// This causes a fault if outcome is a failure
let value = outcome.value  // ⚠️ fault if outcome.isFailure
```

Faults are not catchable in the way exceptions are in other languages. There is no `try/catch` syntax in Kairo v0.1. Faults signal programmer error, not domain error. The correct response to a fault is to fix the code that caused it, not to add a handler around it.

<Note>
  Think of faults as the equivalent of null-pointer exceptions or index-out-of-bounds errors in other languages — they indicate that the program reached a state the developer did not account for. `Result` is for states you anticipate; faults are for states you should have prevented.
</Note>

## Full Example

Here is a complete example showing a function that validates a customer name, an error `enum`, and a caller that handles both outcomes:

```kairo theme={null}
module Customers.Validation

public enum NameValidationError {
    Empty
    TooLong
    ContainsInvalidCharacters
}

public func validateCustomerName(input: Text): Result<Text, NameValidationError> {
    if input.isEmpty() {
        return Result.failure(NameValidationError.Empty)
    }

    if input.length() > 100 {
        return Result.failure(NameValidationError.TooLong)
    }

    if not input.isAlphanumericWithSpaces() {
        return Result.failure(NameValidationError.ContainsInvalidCharacters)
    }

    return Result.success(input)
}
```

And a caller that uses `match` to handle each case:

```kairo theme={null}
module Customers.Registration

import Customers.Validation

public func registerCustomer(rawName: Text): Result<CustomerId, NameValidationError> {
    let nameResult = validateCustomerName(input: rawName)

    match nameResult.isSuccess {
        false {
            // Propagate the validation error to the caller
            return Result.failure(nameResult.error)
        }
        true {
            let validName = nameResult.value
            let id = CustomerId { value: IdGenerator.next() }
            let customer = Customer(id: id, name: validName)
            CustomerRepository.save(customer: customer)
            return Result.success(id)
        }
    }
}
```

<Tip>
  Keep error enums close to the module that produces them. `NameValidationError` lives in `Customers.Validation` — the module that knows all the ways a name can be invalid. Callers import the type when they need to inspect or propagate it.
</Tip>

## Summary

<CardGroup cols={2}>
  <Card title="Result failure" icon="circle-xmark">
    An expected, domain-meaningful outcome. Return `Result.failure(error)` to signal it. The caller inspects and handles it explicitly.
  </Card>

  <Card title="Fault" icon="triangle-exclamation">
    An unexpected invariant violation. Not a `Result`. Terminates the execution boundary. Fix the code that caused it — there is no catch syntax in v0.1.
  </Card>

  <Card title="Error type design" icon="list">
    Use `enum` for closed sets of failure cases. Use `value` when a case carries structured data. Never use raw `Text` or numbers.
  </Card>

  <Card title="Canonical inspection" icon="code">
    Match on `result.isSuccess`. Access `.value` only when `isSuccess` is `true`. Access `.error` only when `isSuccess` is `false`.
  </Card>
</CardGroup>
