stemedb/ai-lookup/patterns/error-handling.md
jml 9bfa626203 docs: reorganize documentation structure for clarity
Major documentation restructure to improve discoverability and reduce duplication.

## Changes

**Deleted (Archived/Consolidated)**:
- Removed duplicate getting started guides
- Archived outdated planning documents
- Consolidated corpus and configuration docs
- Removed obsolete vision/spec files (superseded by vision.md)
- Cleaned up scrapyard and old PDFs

**New Structure**:
- docs/about/ - Project overview and introduction
- docs/guides/ - User guides (moved from root)
- docs/specs/ - Technical specifications
- docs/sdk/ - SDK documentation (Go)
- docs/references/ - API references
- docs/archive/ - Archived historical docs
- applications/aphoria/docs/advanced/ - Advanced topics
- applications/aphoria/docs/reference/ - CLI reference
- applications/aphoria/docs/archive/ - Archived aphoria docs

**Updated**:
- README.md - New root README with clear navigation
- CONTRIBUTING.md - Contribution guidelines
- CLAUDE.md - Updated paths to new structure
- roadmap.md - Added recent completions

## Files Changed
- 57 files changed
- 1,977 insertions(+)
- 961 deletions(-)

**Net change**: +1,016 lines (added CONTRIBUTING.md, README.md, reorganized content)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 07:33:40 +00:00

2.1 KiB

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.rsSerdeError
  • stemedb-wal/src/error.rsQuarantineError
  • stemedb-storage/src/error.rsStorageError
  • stemedb-ingest/src/error.rsIngestError
  • stemedb-query/src/error.rsQueryError
  • stemedb-api/src/error.rsApiError

The Pattern

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