# Errors

> UStore for Mojo

Every fallible entry point raises `Error` and nothing else, since Mojo allows one error type per function.
An `Error` carries a `Status` shared with the C interface:

```mojo
try:
    db.collection_drop(CollectionID())
except error:
    if error.status == Status.NOT_FOUND:
        pass
    print(error)  # UStore: not-found [ustore_collection_drop]: ...
```

An `Error` keeps the engine mapped while it lives, since its name and message are the engine's own static text.

`from ustore import Status, Error`

## Status

Why a call into the engine failed, the `ustore_status_t` vocabulary verbatim.

```mojo
struct Status
```

An [`Error`](#Error) never carries [`SUCCESS`](#SUCCESS) or [`DEFERRED`](#DEFERRED): only a [`Deferred`](https://www.unum.cloud/docs/ustore/mojo/batches-and-arenas.md#Deferred) reports the latter, and only
until its call is final. [`Library.status_name`](https://www.unum.cloud/docs/ustore/mojo/platform-notes.md#status_name) spells each one as the engine does.

- `SUCCESS` = `Status(Int32(0))`: The call succeeded.
- `DEFERRED` = `Status(Int32(1))`: The call was submitted deferred and is not final yet; the one non-final status.
- `OUT_OF_MEMORY` = `Status(Int32(2))`: An allocation could not be satisfied.
- `READ_ONLY` = `Status(Int32(6))`: The call would change a database opened read-only.
- `IO` = `Status(Int32(7))`: A file or directory could not be opened, read, written, or closed.
- `DEVICE` = `Status(Int32(8))`: A device could not be used, or the executor, database and arena live in different places.
- `MALFORMED` = `Status(Int32(9))`: Stored or supplied data could not be decoded.
- `INTERNAL` = `Status(Int32(10))`: The engine failed in a way no other status names, which points at a defect.
- `UNINITIALIZED` = `Status(Int32(12))`: The call needs a database or transaction that was never opened.
- `CONTENDED` = `Status(Int32(14))`: The call was refused rather than waited for, like a submission to a full deferred table.
- `CANCELLED` = `Status(Int32(15))`: A progress handler stopped the call, which unwound and published nothing.
- `UNSUPPORTED` = `Status(Int32(16))`: The engine or build does not implement what the call asks for.
- `INVALID_ARGUMENT` = `Status(Int32(17))`: An argument is null, contradicts another one, or carries a choice the call does not accept.
- `NOT_FOUND` = `Status(Int32(18))`: A collection, a directory, or a document a modification needs does not exist.
- `ALREADY_EXISTS` = `Status(Int32(19))`: A collection name or a document the call creates is already taken.
- `WRITE_CONFLICT` = `Status(Int32(20))`: A concurrent writer changed a key this transaction wrote; retry the transaction.
- `READ_CONFLICT` = `Status(Int32(21))`: A concurrent writer changed a key this transaction read; retry the transaction.
- `PHANTOM_CONFLICT` = `Status(Int32(22))`: A concurrent writer inserted into a range this transaction scanned; retry the transaction.
- `CAPACITY_EXHAUSTED` = `Status(Int32(23))`: A hard design ceiling was reached.
- `LIBRARY_MISSING` = `Status(Int32(-1))`: Nothing to `dlopen`, the binding's own.
- `SYMBOL_MISSING` = `Status(Int32(-2))`: The library loaded but does not export a symbol the binding needs, the binding's own.
- `VERSION_MISMATCH` = `Status(Int32(-3))`: The library loaded but reports a different major version than the binding's, the binding's own.
- `code` `Int32`: The raw `ustore_status_t` value, kept even when this build does not name it.

Conforms to: `Copyable`, `Deinitable`, `Equatable`, `ImplicitlyCopyable`, `Movable`, `RegisterPassable`, `TrivialRegisterPassable`

## of

Lifts a raw `ustore_status_t`, keeping an unnamed one rather than guessing.

```mojo
def of(code: Int32) -> Self
```

## Error

What went wrong inside the engine, and which entry point it was about.

```mojo
struct Error
```

- `status` `Status`: Which class of failure the engine reported.
- `detail` `StaticString`: The entry point it was about, for a reader rather than for a branch.
- `message` `Optional[Pointer[Scalar[_c_char_dtype()], ImmUntrackedOrigin]]`: The engine's own static message, which outlives the call and needs no freeing.
- `name` `Optional[Pointer[Scalar[_c_char_dtype()], ImmUntrackedOrigin]]`: The engine's spelling of [`status`](https://www.unum.cloud/docs/ustore/mojo/batches-and-arenas.md#status), absent where no engine named it.
- `library` `Optional[Library]`: The engine `message` and [`name`](https://www.unum.cloud/docs/ustore/mojo/batches-and-arenas.md#name) live in, kept mapped for as long as the error is; Mojo would otherwise unload it at the last handle's last use, while the error is still being read.

Conforms to: `Copyable`, `Deinitable`, `ImplicitlyCopyable`, `Movable`, `Writable`

## __init__

A failure the binding caught before any engine could name it.

```mojo
def __init__(out self, status: Status, detail: StringSpan[ImmStaticOrigin])
```

- `status`: Which class of failure it is.
- `detail`: The entry point or binding type it was about.

## write_to

Writes the status name, the entry point, and the engine's own message together.

```mojo
def write_to(self, mut writer: T)
```

- `writer` (mut): The sink the message is appended to.

