# Error Handling Pattern

**Last Updated:** 2026-01-31
**Confidence:** High

## Summary

StemeDB uses `thiserror` for library errors with context chains. No panics in production code. All fallible operations return `Result<T, E>`.

**Key Facts:**
- Library code: `thiserror` for custom error types — ALL error enums MUST use `#[derive(thiserror::Error)]`
- Binary code: `anyhow` for error chaining
- Never use `unwrap()`, `expect()`, `panic!()` in production
- Add context with `.context("what we were doing")?`
- NEVER use manual `impl Display` + `impl Error` for error types — use thiserror derives instead

**Error types in workspace (all use thiserror):**
- `stemedb-core/src/serde.rs` — `SerdeError`
- `stemedb-wal/src/error.rs` — `QuarantineError`
- `stemedb-storage/src/error.rs` — `StorageError`
- `stemedb-ingest/src/error.rs` — `IngestError`
- `stemedb-query/src/error.rs` — `QueryError`
- `stemedb-api/src/error.rs` — `ApiError`

## The Pattern

```rust
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StemeError {
    #[error("assertion not found: {0:?}")]
    NotFound(Hash),

    #[error("invalid signature for agent {agent:?}")]
    InvalidSignature { agent: AgentId },

    #[error("storage error: {0}")]
    Storage(String),

    #[error("serialization error: {0}")]
    Serialization(String),
}

// Usage with context
fn load_assertion(&self, hash: &Hash) -> Result<Assertion, StemeError> {
    let bytes = self.store
        .get(hash.as_bytes())
        .context("failed to read assertion from store")?
        .ok_or(StemeError::NotFound(*hash))?;

    rkyv::from_bytes(&bytes)
        .map_err(|e| StemeError::Serialization(e.to_string()))
}
```

## Error Categories

| Type | Description | Example |
|------|-------------|---------|
| `NotFound` | Data doesn't exist | Missing assertion |
| `InvalidSignature` | Crypto verification failed | Tampered assertion |
| `Storage` | Underlying KV error | Disk full |
| `Serialization` | Encode/decode failed | Corrupt data |

## Related Topics

- [Rust Guidelines](../../.claude/guides/backend/rust-guidelines.md)
- [CODING_GUIDELINES.md](../../../CODING_GUIDELINES.md)
