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

# Errors and Result

> Nominal domain errors and explicit success/failure types.

Domain failures are **nominal error types** and **`Result`** values. Each variant has a name and payload in Go's "errors as values" style.

## Nominal errors

Declare named failure kinds with payloads:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    error UnknownStockKeepingUnit {}

    error InsufficientStock {
    	stockKeepingUnit: String,
    	requested:        Int,
    	available:        Int,
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    type UnknownStockKeepingUnit struct{}

    func (e UnknownStockKeepingUnit) Error() string {
    	return "UnknownStockKeepingUnit"
    }

    type InsufficientStock struct {
    	stockKeepingUnit string
    	requested        int
    	available        int
    }

    func (e InsufficientStock) Error() string { /* ... */ }
    ```
  </Tab>
</Tabs>

Use them with **`ensure … or …`**:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    ensure avail is Ok()
    ensure in.quantity is Max(avail) or InsufficientStock({
    	stockKeepingUnit: in.stockKeepingUnit,
    	requested:        in.quantity,
    	available:        avail,
    })
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    if availErr != nil {
    	return availErr
    }
    if in.quantity > avail {
    	return InsufficientStock{
    		stockKeepingUnit: in.stockKeepingUnit,
    		requested:        in.quantity,
    		available:        avail,
    	}
    }
    ```
  </Tab>
</Tabs>

Each error variant is a distinct type. Callers can branch on structure instead of parsing error strings.

### Simple payload example

A minimal nominal error with one payload field:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    error NotPositive {
    	message: String
    }

    func validatePositive(n Int) {
    	ensure n is GreaterThan(0) or NotPositive({
    		message: "n must be greater than 0",
    	})
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    type NotPositive struct {
    	Message string
    }

    func (e NotPositive) Error() string { return e.Message }

    func validatePositive(n int) error {
    	if !(n > 0) {
    		return NotPositive{Message: "n must be greater than 0"}
    	}
    	return nil
    }
    ```
  </Tab>
</Tabs>

## Result types

Functions that can fail with typed errors return **`Result(Success, Failure)`**. The failure side is constrained to the **`Error`** family today.

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    func okInt() {
    	n := 42
    	ensure n is GreaterThan(0)
    	return n
    }

    func main() {
    	x := okInt()
    	ensure x is Ok()
    	println(x)
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    func okInt() (int, error) {
    	n := 42
    	if !(n > 0) {
    		return 0, /* constraint error */
    	}
    	return n, nil
    }

    func main() {
    	x, err := okInt()
    	if err != nil {
    		panic(err)
    	}
    	println(x)
    }
    ```
  </Tab>
</Tabs>

**`Ok`** and **`Err`** serve as discriminants for **`is`** / **`ensure`**. They are not yet general value constructors for building **`Result`** values at every call site.

## Return inference and implicit returns

Forst infers a function's return type from:

* explicit **`return`** statements
* **`ensure`** (often producing **`Result(S, Error)`** when no return type is declared)
* the **last expression** in the function body when no return type is declared in the signature

When the last statement is an expression and the function has no declared return type, that expression's value becomes the function return. Generated Go emits an explicit **`return`** for it.

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    func g(): Result(Int, Error) {
    	return 1
    }

    func f() {
    	g()
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    func g() (int, error) {
    	return 1, nil
    }

    func f() (int, error) {
    	return g()
    }
    ```
  </Tab>
</Tabs>

Here **`f`** also returns **`Result(Int, Error)`**; generated Go contains **`return g()`**.

Explicit **`return`** is still fine (and clearer when intent is ambiguous):

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    func okInt() {
    	n := 42
    	ensure n is GreaterThan(0)
    	return n
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    func okInt() (int, error) {
    	n := 42
    	if !(n > 0) {
    		return 0, /* constraint error */
    	}
    	return n, nil
    }
    ```
  </Tab>
</Tabs>

### Trailing calls and Go imports

This differs from Go **statement** semantics. A trailing call whose Go signature is **`(T, error)`** is typed in Forst as **`Result(T, Error)`** when its result is used — including as an implicit return:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"languages":{"custom":["/languages/forst.json"]}}
    import "fmt"

    func logAndReport(msg String) {
    	fmt.Println(msg)
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"languages":{"custom":["/languages/forst.json"]}}
    // forst build
    import "fmt"

    func logAndReport(msg string) (int, error) {
    	return fmt.Println(msg)
    }
    ```
  </Tab>
</Tabs>

With no declared return type, **`logAndReport`** returns **`Result(Int, Error)`**, not void. To log for side effects only, use Forst **`println`** / **`print`**, or declare a void return on a [Provider contract method](/docs/language/providers).

## Go interop

Forst folds Go's **`(T, error)`** returns into **`Result(T, Error)`** at the boundary where wired. Generated Go uses idiomatic error returns. Your ops team still reads familiar code.

## Generate client types

Nominal errors can emit tagged shapes in generated `.d.ts` as the TS story matures. Today, prefer **`forst generate`** and treat error payloads as evolving. See [Generate client types](/docs/interop/node/generate-types).

## Compared to Go error structs

In Go you might write:

```go theme={"languages":{"custom":["/languages/forst.json"]}}
type InsufficientStock struct {
	StockKeepingUnit string
	Requested        int
	Available        int
}

func (e InsufficientStock) Error() string { ... }
```

Forst's **`error Name { … }`** syntax makes the intent explicit: this is a **failure variant**, a dedicated type for a specific failure mode rather than a generic struct with an `Error()` method attached by convention.

## Caveats

**Nominal errors** and **`Result`** are **experimental**. Check the [roadmap](/docs/resources/roadmap) before relying on edge cases in production.

### `Result` failure side

The failure type parameter is constrained to the **`Error`** family today. Arbitrary non-**`Error`** failure types are not supported yet.

### `Ok` and `Err` role

**`Ok`** and **`Err`** are discriminants for **`is`** and **`ensure`**. They are not general value constructors at every call site yet.

### Implicit return trap

When a function has no declared return type, a trailing Go call that returns **`(T, error)`** can make the whole function return **`Result(T, Error)`**. That includes **`fmt.Println`** and similar calls. Use **`println`** for void side effects, or declare an explicit return type.

### Nominal errors incomplete

**`ensure`** only failure authoring, **`or`** LUB rules, and TypeScript **`_tag`** export are still maturing. Treat generated error payloads as evolving. See [Generate client types § Caveats](/docs/interop/node/generate-types#caveats).

For **`ensure x is Ok()`** narrowing limits, see [Ensure and narrowing § Caveats](/docs/language/ensure-and-narrowing#caveats).

## Try it

From the Forst repository:

```bash theme={"languages":{"custom":["/languages/forst.json"]}}
task example:nominal-error
task example:result-ensure
task example:union-error-types
```

## Related

<Card title="Ensure and narrowing" icon="filter" href="/docs/language/ensure-and-narrowing">
  How `ensure` connects checks to control flow.
</Card>
