---
name: Core error type
type: architecture-map-page
slice: 05-core-storage-hotkey-build
last_verified: 2026/05/09
---

# Core error type

> **Where you are:** [Architecture map](../README.md) → [Core, Storage, Hotkey, Build](README.md) → Core error type

**Plain English summary.** A single structured error enum every Lumotia crate uses, plus a `Result<T>` alias. Errors serialise to JSON so the frontend can switch behaviour on the variant rather than parse strings.

## At a glance

- File: `crates/core/src/error.rs` (60 LOC).
- External deps: `thiserror 2`, `serde 1`.
- Re-exported as `lumotia_core::{MagnotiaError, Result}`.
- Consumers: every workspace crate. Tauri commands wrap their internal errors in `MagnotiaError` so the frontend (slice 1) sees a stable JSON shape.

## What's in here

### `MagnotiaError` — `crates/core/src/error.rs:11`

`#[derive(Debug, thiserror::Error, Serialize)]` enum:

| Variant | Display string | Notes |
|---|---|---|
| `ModelNotFound(ModelId)` | `model not found: {0}` | Used by registry lookups and the model manager. |
| `ModelNotDownloaded(ModelId)` | `model not downloaded: {0}` | Distinct from `ModelNotFound`: model is registered, files missing. |
| `EngineNotLoaded` | `engine not loaded: call load_model first` | Engine API ordering violation. |
| `TranscriptionFailed(String)` | `transcription failed: {0}` | Wraps Whisper / Parakeet / Moonshine engine errors. |
| `AudioDecodeFailed(String)` | `audio decode failed: {0}` | Symphonia / hound failures (slice 3). |
| `AudioCaptureFailed(String)` | `audio capture failed: {0}` | cpal / native capture failures (slice 3). |
| `DownloadFailed(String)` | `model download failed: {0}` | Resumable download errors. |
| `FileNotFound(PathBuf)` | `file not found: {<displayed>}` | `PathBuf::display()` interpolated. |
| `Storage { kind, operation, detail }` | `{detail}` | Boundary shape produced by `From<lumotia_storage::Error>`. `kind` is the serialisable discriminator (`StorageKind`), `operation` is the typed operation label, `detail` is the storage crate's own `Display` output (no double prefix). |
| `Io(std::io::Error)` | `io error: {0}` | `#[from]` so `?`-conversion from `std::io::Error` is automatic. |
| `Other(String)` | `{0}` | Catch-all bucket. |

### `Result<T>` — `crates/core/src/error.rs:60`

```rust
pub type Result<T> = std::result::Result<T, MagnotiaError>;
```

Every public function in the workspace that can fail returns `lumotia_core::Result<T>` rather than `std::result::Result<T, MagnotiaError>` so the imports stay short.

## Data flow / contract

- All variants are `Serialize`-able. `std::io::Error` does not derive `Serialize`, so the `Io` variant uses a custom `serialize_with` adaptor (`serialize_io_error` at `crates/core/src/error.rs:53`) that emits the error's `Display` string.
- Variants do not carry source-location information. The storage CRUD layer attaches context via the typed `lumotia_storage::Error::Query { operation, source }` shape; the `operation` label survives into `MagnotiaError::Storage.operation` at the boundary.
- Tauri serialises the enum verbatim. The frontend can switch on the discriminant by reading the JSON tag (the variant name).

## Watch-outs

- **No `From<sqlx::Error>` impl in core.** The storage crate manually converts every sqlx error to a typed `lumotia_storage::Error::Query` with an operation label, then `From<storage::Error> for MagnotiaError` (defined inside the storage crate to avoid a `core -> storage` dependency cycle) flattens it into `MagnotiaError::Storage { kind, operation, detail }` at the boundary. Adding an automatic `From<sqlx::Error>` would erase the per-site operation label; the explicit map step is intentional.
- **No `Source` chain.** `thiserror` would let you wrap source errors in fields with `#[source]` for chained `Display`. Today every wrapped error is flattened to `String` to keep the JSON shape simple.
- **`Other(String)` is a leaky bucket.** New error categories should get their own variant rather than reaching for `Other`. Audit `Other` usage if the error log starts hiding distinct failure modes behind the same string.

## See also

- [Public types and enums](core-types-and-enums.md)
- [Storage CRUD surfaces](storage-overview.md)
