coven_replication/sync/store/circles/
error.rs1use crate::sync::store::{StoreError, StoreRegistrationError};
2use coven_protocol::circle::{CircleId, CircleTransitionError};
3use coven_protocol::objects::StoreObjectError;
4
5#[derive(Debug, thiserror::Error)]
6pub enum CircleOperationError {
7 #[error("database: {0}")]
8 Database(coven_database::DbError),
9 #[error("circle protocol state is absent: {0}")]
10 MissingState(&'static str),
11 #[error("circle protocol state is invalid: {0}")]
12 InvalidState(String),
13 #[error("circle state reduction: {0}")]
14 State(#[from] coven_protocol::circle_activation::CircleStateError),
15 #[error("circle row blob reference: {0}")]
16 RowBlob(#[from] coven_protocol::blob::RowBlobRefError),
17 #[error("circle construction: {0}")]
18 Construction(#[from] CircleTransitionError),
19 #[error("Circle epoch-close response: {0}")]
20 EpochCloseResponse(#[source] CircleTransitionError),
21 #[error("circle protocol: {0}")]
22 Protocol(#[from] coven_protocol::store_commit::StoreProtocolError),
23 #[error("circle roster: {0}")]
24 Roster(#[from] coven_protocol::circle_roster::CircleRosterError),
25 #[error("circle row routing key: {0}")]
26 RowRoutingKey(#[from] coven_protocol::circle::RowRoutingKeyError),
27 #[error("circle snapshot image: {0}")]
28 SnapshotImage(#[from] coven_database::SnapshotImageError),
29 #[error("circle encryption: {0}")]
30 Encryption(#[from] coven_keys::encryption::EncryptionError),
31 #[error("circle key operation: {0}")]
32 Key(#[from] coven_keys::keys::KeyError),
33 #[error("circle JSON: {0}")]
34 Json(#[from] serde_json::Error),
35 #[error("circle storage: {0}")]
36 Storage(#[from] coven_protocol::objects::StorageError),
37 #[error("circle object: {0}")]
38 Object(#[from] StoreObjectError),
39 #[error("circle blob download: {0}")]
40 BlobDownload(#[from] crate::sync::store::blob::BlobDownloadFailureCause),
41 #[error("Store publication: {0}")]
42 StoreOutbound(#[from] StoreError),
43 #[error("Store device registration: {0}")]
44 StoreRegistration(#[from] StoreRegistrationError),
45 #[error("circle writer authorization: {0}")]
46 WriterAuthorization(#[source] Box<crate::sync::store::StoreWriterAuthorizationError>),
47 #[error("circle sync cycle: {0}")]
48 SyncCycle(#[source] Box<crate::sync::cycle::SyncCycleFailure>),
49 #[error("circle Store pull: {0}")]
50 StorePull(#[source] Box<crate::sync::store::StorePullError>),
51 #[error("circle membership chain: {0}")]
52 AnchoredChain(#[source] Box<crate::sync::store::AnchoredChainError>),
53 #[error("circles require opaque cloud storage")]
54 BrowsableStorage,
55 #[error("circle operation journal: {0}")]
56 Journal(#[from] coven_protocol::circle_journal::CircleJournalError),
57 #[error("circle operation journal state: {0}")]
58 JournalState(String),
59 #[error("circle operation {circle_id} is blocked: {block}")]
60 Blocked {
61 circle_id: CircleId,
62 block: coven_protocol::circle::CircleOperationBlock,
63 },
64 #[error("circle {circle_id} requires rotation: its roster names removed Store members {removed_members:?}")]
65 RotationRequired {
66 circle_id: CircleId,
67 removed_members: Vec<String>,
68 },
69 #[error("device excluded from circle {circle_id} close {close_id} must reset from the successor bootstrap before publishing")]
70 ExcludedDeviceMustReset {
71 circle_id: CircleId,
72 close_id: coven_protocol::circle::CircleEpochCloseId,
73 },
74 #[error("circle {circle_id} has no retained control conflict to resolve")]
75 NotConflicted { circle_id: CircleId },
76 #[error("circle {circle_id} control conflict does not retain the chosen branch")]
77 ChosenBranchNotRetained { circle_id: CircleId },
78 #[error("circle {circle_id} control conflict cannot be resolved to its closing branch: an epoch close binds its participant responses to the closing control, so a resolution successor under a new control coordinate would strand them; resolve to a non-closing branch to discard the close instead")]
79 ResolveToClosingBranch { circle_id: CircleId },
80 #[error("circle {circle_id} has no local epoch close waiting for cancellation")]
81 NoCloseToCancel { circle_id: CircleId },
82 #[error("circle {circle_id} has no local epoch close waiting for device exclusion")]
83 NoCloseToExclude { circle_id: CircleId },
84 #[error("device {device_id} is not a participant in circle {circle_id}'s epoch close")]
85 DeviceNotACloseParticipant {
86 circle_id: CircleId,
87 device_id: coven_protocol::store_commit::StoreDeviceId,
88 },
89 #[error("circle operation {operation_id} is not blocked")]
90 NotBlocked {
91 operation_id: coven_protocol::circle::CircleOperationId,
92 },
93 #[error("circle operation {operation_id} discard requires verified permanent nonactivation; it never assumes an unseen candidate failed to activate")]
94 DiscardRequiresNonactivation {
95 operation_id: coven_protocol::circle::CircleOperationId,
96 },
97 #[error("circle {circle_id} has an unresolved control conflict")]
98 Conflicted { circle_id: CircleId },
99 #[error("circle {circle_id} is deleted")]
100 Deleted { circle_id: CircleId },
101 #[error("circle command channel is closed")]
102 CommandChannelClosed,
103 #[error("circle command ended without a reply")]
104 ReplyChannelClosed,
105}
106
107impl From<coven_database::DbError> for CircleOperationError {
108 fn from(error: coven_database::DbError) -> Self {
109 match error {
110 coven_database::DbError::ExcludedDeviceMustReset {
111 circle_id,
112 close_id,
113 } => Self::ExcludedDeviceMustReset {
114 circle_id,
115 close_id,
116 },
117 other => Self::Database(other),
118 }
119 }
120}
121
122impl From<crate::sync::store::StoreWriterAuthorizationError> for CircleOperationError {
123 fn from(error: crate::sync::store::StoreWriterAuthorizationError) -> Self {
124 Self::WriterAuthorization(Box::new(error))
125 }
126}
127
128impl From<crate::sync::cycle::SyncCycleFailure> for CircleOperationError {
129 fn from(error: crate::sync::cycle::SyncCycleFailure) -> Self {
130 Self::SyncCycle(Box::new(error))
131 }
132}
133
134impl From<crate::sync::store::StorePullError> for CircleOperationError {
135 fn from(error: crate::sync::store::StorePullError) -> Self {
136 Self::StorePull(Box::new(error))
137 }
138}
139
140impl From<crate::sync::store::AnchoredChainError> for CircleOperationError {
141 fn from(error: crate::sync::store::AnchoredChainError) -> Self {
142 Self::AnchoredChain(Box::new(error))
143 }
144}