aion_store/error.rs
1//! `StoreError` taxonomy.
2
3use aion_core::WorkflowId;
4
5/// Errors returned by [`crate::ReadableEventStore`] and [`crate::EventStore`] implementations.
6#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
7pub enum StoreError {
8 /// The workflow history head did not match the caller's optimistic-concurrency guard.
9 #[error(
10 "sequence conflict (double-writer bug indicator): expected workflow head {expected}, found {found}"
11 )]
12 SequenceConflict {
13 /// Sequence number the caller expected to be the current workflow head.
14 expected: u64,
15 /// Sequence number currently stored as the workflow head.
16 found: u64,
17 },
18
19 /// Reserved for operations that target a must-exist workflow; read and query methods return
20 /// empty results, not `NotFound`, for absent workflows.
21 #[error("workflow {workflow_id} was not found")]
22 NotFound {
23 /// Workflow identifier targeted by the must-exist operation.
24 workflow_id: WorkflowId,
25 },
26
27 /// An assistant-session transcript append named a session with no record.
28 ///
29 /// Deliberately NOT a silent create: a transcript with no session record is
30 /// a conversation with no owner, no harness and no subject, which every
31 /// read surface would then have to invent an answer for. Shaped like
32 /// [`Self::NotFound`] — the must-exist refusal — but carrying a session id
33 /// rather than a workflow id, because an assistant session is not a workflow
34 /// and has no workflow identity to borrow.
35 #[error("assistant session {session_id} was not found")]
36 AssistantSessionNotFound {
37 /// The session the append or mutation targeted.
38 session_id: String,
39 },
40
41 /// The targeted shard is owned by a different node: a quorum write was fenced
42 /// because this node is not the current owner of the workflow's shard. Unlike
43 /// [`Self::Backend`] this is a typed, *retryable* routing signal — the caller
44 /// (or the request-routing edge) should re-resolve the shard's owner and retry
45 /// or forward, rather than treating it as an opaque internal failure. Emitted
46 /// only on the distributed (`[store.cluster]`) replication path.
47 #[error("shard {shard} is owned by another node (not owner)")]
48 NotOwner {
49 /// The distribution shard the fenced workflow's durable state lives on.
50 shard: usize,
51 },
52
53 /// A list request the store refuses on its face: a zero page limit, or a
54 /// cursor that was not minted under the request's own namespace, filter,
55 /// and sort. Never a backend fault; the caller's input is wrong.
56 #[error("invalid list query: {0}")]
57 InvalidQuery(String),
58
59 /// Backend-specific failure mapped into the store contract's closed error surface.
60 #[error("store backend error: {0}")]
61 Backend(String),
62
63 /// Serialization or deserialization failure while crossing the store boundary.
64 #[error("store serialization error: {0}")]
65 Serialization(String),
66}