> ## 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.

# Functions that can fail

> A function returns a value or a failure. Check success before you use the value.

A **`Result`** records that a function can either return a value or one of its
expected errors. Check success before you use the value. On failure, handle
the error locally or let it return to the caller.

## A value or a failure

A function that can fail returns `Result(Success, Failure)`. The first type is
the successful value. The second type is the error. The failure type must belong
to the `Error` family.

After `placeOrder` returns a `Result`, continue only on success:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    order := placeOrder({
    	stockKeepingUnit: "ITEM-1",
    	quantity:         2,
    })
    ensure order
    println(order)
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    // forst build
    order, err := placeOrder(PlaceOrderInput{
    	stockKeepingUnit: "ITEM-1",
    	quantity:         2,
    })
    if err != nil {
    	return err
    }
    println(order)
    ```
  </Tab>
</Tabs>

`ensure order` is the same as `ensure order is Ok()`. On failure, the function
that contains this `ensure` returns `order`'s error (except in `main` and Go
tests). After the check, `order` is the successful value.

See [Return a named error](/docs/language/named-errors) for how to declare the
failure types, and [Check a value](/docs/language/check-a-value) for short forms of
`ensure`.

## How a function gets that type

Forst can infer this return type when `ensure` introduces a failure path.

<Tabs>
  <Tab title="Forst">
    ```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    func reserve(quantity Int) {
    	ensure quantity is GreaterThan(0)
    	return quantity
    }

    func main() {
    	reserved := reserve(2)
    	ensure reserved is Ok()
    	println(reserved)
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    // forst build
    import "errors"

    func reserve(quantity int) (int, error) {
    	if !(quantity > 0) {
    		return 0, errors.New("ensure quantity is Int.GreaterThan(0): want > 0")
    	}
    	return quantity, nil
    }

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

The check in `reserve` can fail, so Forst infers `Result(Int, Error)`. The
caller uses `ensure reserved is Ok()` before using the successful value.

A function with no success value that still has a failure path (body `ensure`
with no success return) infers `Result(Void, Error)`. Generated Go writes that
as `func() error`. Callers treat the binding like other Results
(`ensure result` or `ensure result is Ok()`).

**`Ok()`** and **`Err()`** identify the two sides of a `Result` during `is` and
`ensure` checks. They are checks. General `Ok(value)` and `Err(error)`
constructors are still in development.

Bare `ensure order is Ok()` with no `else` gives the caller a `Result` return
type (except `main` / Go tests) and returns the error from `order`. Use
`if order is Ok()` when you want local handling without changing the caller's
return type.

### Let Forst infer the return type

Forst looks at three places when a function has no declared return type.

* Each explicit `return`
* Each `ensure` that can fail
* The final expression in the function body

If the final statement is an expression, its value becomes the return value.
Generated Go adds the explicit `return`.

<Tabs>
  <Tab title="Forst">
    ```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    func g(): Result(Int, Error) {
    	return 1
    }

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

  <Tab title="Generated Go">
    ```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    // forst build
    func g() (int, error) {
    	return 1, nil
    }

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

Here `g` returns `Result(Int, Error)`. The final call to `g()` means that `f`
returns the same type. Generated Go contains `return g()`.

Use an explicit `return` whenever it makes the intent easier to see.

## Stay in the function on failure

Use `if` when failure should not return from the function. Forst refines the
value inside the matching branch. Outside the branch, `order` is still the
full `Result`:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    order := placeOrder({
    	stockKeepingUnit: "ITEM-1",
    	quantity:         2,
    })
    if order is Ok() {
    	println(order)
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    // forst build — Result becomes a value and an error in Go
    order, orderErr := placeOrder(PlaceOrderInput{
    	stockKeepingUnit: "ITEM-1",
    	quantity:         2,
    })
    if orderErr == nil {
    	println(order)
    }
    ```
  </Tab>
</Tabs>

## Check which error you got

Use `Err(ErrorName)` when each error needs a different response. First declare
a closed list of errors:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    error ParseFailed {
    	code: Int,
    }

    error IoFailed {
    	path: String,
    }

    type LoadFailed = ParseFailed | IoFailed

    func load(): Result(Int, LoadFailed) {
    	return 0
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    // forst build
    // LoadFailed is a closed union of nominal errors (only these types implement it).
    type LoadFailed interface {
    	isLoadFailed()
    }

    type IoFailed struct {
    	path string
    }

    type ParseFailed struct {
    	code int
    }

    func (e IoFailed) Error() string { return "error" }
    func (e ParseFailed) Error() string { return "error" }

    func (e IoFailed) ForstErrorTag() string { return "main/IoFailed" }
    func (e ParseFailed) ForstErrorTag() string { return "main/ParseFailed" }

    func (IoFailed) isLoadFailed() {}
    func (ParseFailed) isLoadFailed() {}

    func load() (int, error) {
    	return 0, nil
    }
    ```
  </Tab>
</Tabs>

Then branch on one of them:

<Tabs>
  <Tab title="Forst">
    ```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    error ParseFailed {
    	code: Int,
    }

    error IoFailed {
    	path: String,
    }

    type LoadFailed = ParseFailed | IoFailed

    func load(): Result(Int, LoadFailed) {
    	return 0
    }

    func handleParseFailed(err ParseFailed) {}

    func inspect() {
    	result := load()
    	if result is Err(ParseFailed) {
    		handleParseFailed(result)
    	}
    }
    ```
  </Tab>

  <Tab title="Generated Go">
    ```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
    // forst build
    type LoadFailed interface {
    	isLoadFailed()
    }

    type IoFailed struct {
    	path string
    }

    type ParseFailed struct {
    	code int
    }

    func (e IoFailed) Error() string { return "error" }
    func (e ParseFailed) Error() string { return "error" }

    func (e IoFailed) ForstErrorTag() string { return "main/IoFailed" }
    func (e ParseFailed) ForstErrorTag() string { return "main/ParseFailed" }

    func (IoFailed) isLoadFailed() {}
    func (ParseFailed) isLoadFailed() {}

    func load() (int, error) {
    	return 0, nil
    }

    func handleParseFailed(err ParseFailed) {}

    func inspect() {
    	result, resultErr := load()
    	if func() bool {
    		if resultErr == nil {
    			return false
    		}
    		_, ok := resultErr.(ParseFailed)
    		return ok
    	}() {
    		_ = result
    		handleParseFailed(resultErr.(ParseFailed))
    	}
    }
    ```
  </Tab>
</Tabs>

Inside the branch, `result` is a `ParseFailed`. See
[List alternatives](/docs/language/union-and-intersection-types#list-the-errors-a-function-can-return)
for error unions.

## Handle Go functions with several returns

Go functions often return a value and an error. Forst preserves all returned
values when you capture the call in one variable. The resulting type is a
**`Tuple`**.

Split the values and check the error when your Forst function should return a
`Result`.

```ft theme={"theme":{"light":"github-light-default","dark":"dark-plus"}}
n, err := pkg.F()
ensure !err
return n
```

This is the same shape as ordinary Go error handling. Generated Go uses the
usual value and error returns. Because `err` has type `Error`, the missing
`else` returns that error. Writing `ensure !err else err` remains valid
but is redundant.

### Result and Tuple stay separate

The two types make different promises. A `Result` contains one outcome. It is
either a success or a failure. A `Tuple` preserves every returned position, and
several positions may contain meaningful values at the same time.

| Type | Where it comes from | How to inspect it |
| - | - | - |
| `Result(S, F)` | Forst functions with success and failure paths | Use `Ok()` and `Err()` checks |
| `Tuple(T₁…Tₙ)` | A call with several returns captured in one value | Read or split its ordered values |

<AccordionGroup>
  <Accordion title="Why Forst never turns several returns into a Result automatically">
    `Result` means that you get a value or an error. Some calls can return both.
    For example, a read can return its final bytes together with an end of input
    signal. The bytes still need to be processed.

    Forst cannot learn this behavior from the return types. A pair containing a
    value and an error looks the same in both cases. Keeping a list of special
    calls would miss new packages and functions.

    Forst therefore never turns several return values into a `Result`
    automatically. This keeps `Ok()` and `Err()` trustworthy. `Ok()` always means
    that there is no error. `Err()` always means that there is no success value.

    * A call with several returns always becomes a `Tuple` when captured in one
      value. Every returned value stays available.
    * A `Result` comes from a function with exclusive success and failure paths.
      `return` and `ensure` make those paths explicit.
    * Conversion between `Tuple` and `Result` is unavailable. `Ok()` and `Err()`
      only apply to `Result`.
    * When you know a call has exclusive outcomes, split its values and use
      `ensure !err` before returning the success value.
    * The rule applies to every package. It needs no catalog or project setting.

    If a call with several returns is the final expression of an inferred function,
    the function also returns a `Tuple`. Split the values as shown above when you
    want a `Result`.

    For calls used only for side effects, prefer Forst `println` or `print`. A
    [Provider contract method](/docs/language/providers) can also declare an explicit
    return type.
  </Accordion>
</AccordionGroup>

## Use errors from TypeScript

Generated TypeScript clients can expose error payloads as tagged shapes. This
part of the client API is still evolving. Generate the client with
`forst generate` and see [Generate client types](/docs/interop/invoke/generate-types)
for the current output.

## Caveats

`Result` is experimental. Check the
[roadmap](/docs/resources/roadmap) before relying on edge cases in production.

### Failure side

The failure type must belong to the `Error` family. Other failure types are not
supported yet.

### `Ok` and `Err` role

`Ok` and `Err` support `is` and `ensure` checks. General value constructors are
still in development.

### Final Go calls

A final Go call with several return values produces a `Tuple` during return
inference. Split the values and check the error when you need a `Result`.

For limits around `ensure order is Ok()`, see
[Check a value](/docs/language/check-a-value#caveats).

## Examples

See the Result examples on GitHub:

* [`examples/in/result_ensure.ft`](https://github.com/forst-lang/forst/blob/main/examples/in/result_ensure.ft)
* [`examples/in/result_void_ensure.ft`](https://github.com/forst-lang/forst/blob/main/examples/in/result_void_ensure.ft)
* [`examples/in/result_unwrap_propagate.ft`](https://github.com/forst-lang/forst/blob/main/examples/in/result_unwrap_propagate.ft)
* [`examples/in/result_if.ft`](https://github.com/forst-lang/forst/blob/main/examples/in/result_if.ft)
* [`examples/in/union_error_types.ft`](https://github.com/forst-lang/forst/blob/main/examples/in/union_error_types.ft)

## Related

<CardGroup cols={2}>
  <Card title="Return a named error" icon="triangle-exclamation" href="/docs/language/named-errors">
    Declare and return named failures.
  </Card>

  <Card title="Check a value" icon="filter" href="/docs/language/check-a-value">
    How ensure connects checks to control flow.
  </Card>

  <Card title="List alternatives" icon="code-branch" href="/docs/language/union-and-intersection-types">
    Closed sets of named errors.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.