Skip to main content

post_cortex_memory/
error.rs

1// Copyright (c) 2025, 2026 Julius ML
2// Licensed under the MIT License. See LICENSE at the workspace root.
3
4//! Typed error hierarchy for `post-cortex-memory`.
5//!
6//! Composes the lower-layer errors from `post-cortex-storage` and
7//! `post-cortex-embeddings` plus orchestrator-specific variants
8//! (pipeline backpressure, circuit breaker open, session not found).
9
10use thiserror::Error;
11use uuid::Uuid;
12
13/// Errors produced by the orchestrator layer.
14#[derive(Debug, Error)]
15pub enum Error {
16    /// Underlying storage error.
17    #[error(transparent)]
18    Storage(#[from] post_cortex_storage::error::Error),
19
20    /// Underlying embeddings / vector-db error.
21    #[error(transparent)]
22    Embeddings(#[from] post_cortex_embeddings::error::Error),
23
24    /// Domain-level error from `post-cortex-core`.
25    #[error(transparent)]
26    Domain(#[from] post_cortex_core::SystemError),
27
28    /// Session not found in the active cache or backend.
29    #[error("session not found: {0}")]
30    SessionNotFound(Uuid),
31
32    /// Circuit breaker is open, request rejected without trying the
33    /// underlying operation.
34    #[error("circuit breaker open: {0}")]
35    CircuitBreaker(String),
36
37    /// Pipeline applied backpressure — the bounded queue was full.
38    #[error("pipeline backpressure on {queue}")]
39    Backpressure {
40        /// Name of the saturated queue.
41        queue: &'static str,
42    },
43
44    /// Pipeline worker shut down before the work could be processed.
45    #[error("pipeline worker shut down: {queue}")]
46    WorkerShutdown {
47        /// Name of the shut-down queue.
48        queue: &'static str,
49    },
50
51    /// Operation timed out.
52    #[error("operation timeout after {ms}ms")]
53    Timeout {
54        /// Elapsed wall-clock time in milliseconds.
55        ms: u64,
56    },
57
58    /// Catch-all for migrating call sites that still use `anyhow`.
59    #[error(transparent)]
60    External(#[from] anyhow::Error),
61}
62
63/// Crate-level result alias.
64pub type Result<T, E = Error> = std::result::Result<T, E>;
65
66impl From<crate::pipeline::PipelineError> for Error {
67    fn from(err: crate::pipeline::PipelineError) -> Self {
68        match err {
69            crate::pipeline::PipelineError::Backpressure { queue } => Self::Backpressure { queue },
70            crate::pipeline::PipelineError::WorkerShutdown { queue } => {
71                Self::WorkerShutdown { queue }
72            }
73        }
74    }
75}
76
77impl Error {
78    /// A stable discriminant for metrics / structured logs.
79    #[must_use]
80    pub fn kind(&self) -> &'static str {
81        match self {
82            Self::Storage(_) => "storage",
83            Self::Embeddings(_) => "embeddings",
84            Self::Domain(_) => "domain",
85            Self::SessionNotFound(_) => "session_not_found",
86            Self::CircuitBreaker(_) => "circuit_breaker",
87            Self::Backpressure { .. } => "backpressure",
88            Self::WorkerShutdown { .. } => "worker_shutdown",
89            Self::Timeout { .. } => "timeout",
90            Self::External(_) => "external",
91        }
92    }
93}