# Errors

> UStore for Python

Every failure raises a subclass of `ustore.Error`, itself a `RuntimeError`, and each carries the status the C ABI reported as its `status` attribute, a `ustore.Status` member:

```python
transaction = database.transaction(ustore.Watch.KEYS)
try:
    transaction.set(key, value)
    transaction.commit(ustore.Durability.FLUSHED)
except ustore.ConflictError as error:
    assert error.status in (ustore.Status.WRITE_CONFLICT, ustore.Status.READ_CONFLICT)
finally:
    transaction.close()
```

`SUCCESS` and `DEFERRED` raise nothing, and every other member has its own class, which also derives the built-in naming the same fault where one exists:

- `OUT_OF_MEMORY` → `OutOfMemoryError`, a `MemoryError`
- `READ_ONLY` → `ReadOnlyError`
- `IO` → `InputOutputError`, an `OSError`
- `DEVICE` → `DeviceError`
- `MALFORMED` → `MalformedError`, a `ValueError`
- `INTERNAL` → `InternalError`
- `UNINITIALIZED` → `UninitializedError`
- `CONTENDED` → `ContendedError`
- `CANCELLED` → `CancelledError`
- `UNSUPPORTED` → `UnsupportedError`, a `NotImplementedError`
- `INVALID_ARGUMENT` → `InvalidArgumentError`, a `ValueError`
- `NOT_FOUND` → `NotFoundError`, a `KeyError`
- `ALREADY_EXISTS` → `AlreadyExistsError`, a `ValueError`
- `WRITE_CONFLICT` → `WriteConflictError`, a `ConflictError`
- `READ_CONFLICT` → `ReadConflictError`, a `ConflictError`
- `PHANTOM_CONFLICT` → `PhantomConflictError`, a `ConflictError`
- `CAPACITY_EXHAUSTED` → `CapacityExhaustedError`, an `OverflowError`

So `except KeyError` catches a missing collection, and `except ConflictError` is the one clause a retry loop needs for the three conflicts.
A database `view_rocksdb` opened raises `ReadOnlyError` from every call that would change it: writes, removes, transactions, collection creates and drops, clears and compactions.
A failure the binding catches before the boundary raises the class the engine would have raised for the same fault: a closed database, transaction, snapshot or executor raises `UninitializedError`, a view of a collection holding another modality raises `InvalidArgumentError`, and a count of values that disagrees with the count of keys raises `InvalidArgumentError` too.
An argument of the wrong Python type raises `TypeError`, and a snapshot refuses a write with one.

`import ustore`

`from ustore import Error`

## Status

What went wrong, valued as `ustore_status_t`: [`Error.status`](#status) and [`Deferred.status`](#status).

```python
class Status(IntEnum)
```

- `SUCCESS` = `0`
- `DEFERRED` = `1`
- `OUT_OF_MEMORY` = `2`
- `READ_ONLY` = `6`
- `IO` = `7`
- `DEVICE` = `8`
- `MALFORMED` = `9`
- `INTERNAL` = `10`
- `UNINITIALIZED` = `12`
- `CONTENDED` = `14`
- `CANCELLED` = `15`
- `UNSUPPORTED` = `16`
- `INVALID_ARGUMENT` = `17`
- `NOT_FOUND` = `18`
- `ALREADY_EXISTS` = `19`
- `WRITE_CONFLICT` = `20`
- `READ_CONFLICT` = `21`
- `PHANTOM_CONFLICT` = `22`
- `CAPACITY_EXHAUSTED` = `23`

## OutOfMemoryError

An allocation could not be satisfied.

```python
class OutOfMemoryError(Error, MemoryError)
```

## InvalidArgumentError

An argument is null, contradicts another one, or carries a choice the call does not accept, like a collection of another modality.

```python
class InvalidArgumentError(Error, ValueError)
```

## UninitializedError

The call needs a handle that was never opened or is closed, or reads a result whose arena a later call rewound.

```python
class UninitializedError(Error)
```

## UnsupportedError

The engine or this build does not implement what the call asks for.

```python
class UnsupportedError(Error, NotImplementedError)
```

## InputOutputError

A file or directory could not be opened, read, written, or closed.

```python
class InputOutputError(Error, OSError)
```

## MalformedError

Stored or supplied data could not be decoded, like a corrupted file or an invalid document.

```python
class MalformedError(Error, ValueError)
```

## NotFoundError

A collection, a directory, or a document a modification needs does not exist.

```python
class NotFoundError(Error, KeyError)
```

## AlreadyExistsError

A collection name or a document the call creates is already taken, or a raw medium's first slot is not free.

```python
class AlreadyExistsError(Error, ValueError)
```

## ConflictError

A concurrent writer touched what this transaction wrote, read or scanned: the one base a retry loop catches.

```python
class ConflictError(Error)
```

## WriteConflictError

A concurrent writer changed a key this transaction wrote; retry the transaction.

```python
class WriteConflictError(ConflictError)
```

## ReadConflictError

A concurrent writer changed a key this transaction read; retry the transaction.

```python
class ReadConflictError(ConflictError)
```

## PhantomConflictError

A concurrent writer inserted into a range this transaction scanned; retry the transaction.

```python
class PhantomConflictError(ConflictError)
```

## CapacityExhaustedError

A hard design ceiling was reached.

```python
class CapacityExhaustedError(Error, OverflowError)
```

## DeviceError

A device could not be selected or claimed, or the executor, database and arena of a call live apart.

```python
class DeviceError(Error)
```

## InternalError

The engine failed in a way no other status names, which points at a defect.

```python
class InternalError(Error)
```

## ContendedError

The call was refused rather than waited for: a full deferred table, an arena serving another call or exporting a buffer, or a transaction serving another call; retry it once that one finishes or the buffer is released.

```python
class ContendedError(Error)
```

## CancelledError

A progress callback stopped the call, which unwound and published nothing.

```python
class CancelledError(Error)
```

## ReadOnlyError

The call would change a database opened read-only, as [`Database.view_rocksdb`](https://www.unum.cloud/docs/ustore/python/quickstart.md#view_rocksdb) opens one.

```python
class ReadOnlyError(Error)
```

## Error

Every failure the engine reports, one subclass per status shared with the C ABI.

```python
class Error(RuntimeError)
```

## status

The status, such as [`Status.WRITE_CONFLICT`](#WRITE_CONFLICT) or [`Status.OUT_OF_MEMORY`](#OUT_OF_MEMORY).

```python
status: Status
```

