canic_backup/plan/
error.rs1use crate::discovery::DiscoveryError;
2use thiserror::Error as ThisError;
3
4#[derive(Debug, ThisError)]
9pub enum BackupPlanError {
10 #[error("field {0} must not be empty")]
11 EmptyField(&'static str),
12
13 #[error("field {field} must be a valid principal: {value}")]
14 InvalidPrincipal { field: &'static str, value: String },
15
16 #[error("field {field} must be a 64-character hex topology hash: {value}")]
17 InvalidTopologyHash { field: &'static str, value: String },
18
19 #[error("field {field} must be a unix timestamp marker: {value}")]
20 InvalidTimestamp { field: &'static str, value: String },
21
22 #[error("backup plan has no targets")]
23 EmptyTargets,
24
25 #[error("backup plan has no phases")]
26 EmptyPhases,
27
28 #[error("duplicate backup target {0}")]
29 DuplicateTarget(String),
30
31 #[error("duplicate backup operation id {0}")]
32 DuplicateOperationId(String),
33
34 #[error("operation {operation_id} has order {order}, expected {expected}")]
35 OperationOrderMismatch {
36 operation_id: String,
37 order: u32,
38 expected: u32,
39 },
40
41 #[error("normal backup scope must not include root")]
42 RootIncludedWithoutMaintenance,
43
44 #[error("maintenance root scope must include root")]
45 MaintenanceRootExcludesRoot,
46
47 #[error("selected scope root {0} is not present in plan targets")]
48 SelectedRootNotInTargets(String),
49
50 #[error("non-root-fleet scope must not declare a selected subtree root")]
51 NonRootFleetHasSelectedRoot,
52
53 #[error("target {0} has no proven control authority")]
54 UnprovenControlAuthority(String),
55
56 #[error("target {0} has no proven snapshot read authority")]
57 UnprovenTargetSnapshotReadAuthority(String),
58
59 #[error("target {0} must be controllable by root for this plan")]
60 MissingRootController(String),
61
62 #[error("target {0} has no control authority receipt")]
63 MissingControlAuthorityReceipt(String),
64
65 #[error("target {0} has no snapshot read authority receipt")]
66 MissingSnapshotReadAuthorityReceipt(String),
67
68 #[error("authority receipt targets unknown canister {0}")]
69 UnknownAuthorityReceiptTarget(String),
70
71 #[error("duplicate authority receipt for target {0}")]
72 DuplicateAuthorityReceipt(String),
73
74 #[error("authority receipt plan id {actual} does not match plan {expected}")]
75 AuthorityReceiptPlanMismatch { expected: String, actual: String },
76
77 #[error("authority receipt preflight id {actual} does not match preflight {expected}")]
78 AuthorityReceiptPreflightMismatch { expected: String, actual: String },
79
80 #[error("preflight receipt plan id {actual} does not match plan {expected}")]
81 PreflightReceiptPlanMismatch { expected: String, actual: String },
82
83 #[error("preflight receipt id {actual} does not match preflight {expected}")]
84 PreflightReceiptIdMismatch { expected: String, actual: String },
85
86 #[error(
87 "preflight receipt {preflight_id} is not valid yet at {as_of}; validated at {validated_at}"
88 )]
89 PreflightReceiptNotYetValid {
90 preflight_id: String,
91 validated_at: String,
92 as_of: String,
93 },
94
95 #[error("preflight receipt {preflight_id} expired at {expires_at}; checked at {as_of}")]
96 PreflightReceiptExpired {
97 preflight_id: String,
98 expires_at: String,
99 as_of: String,
100 },
101
102 #[error("preflight receipt {preflight_id} has invalid validity window")]
103 PreflightReceiptInvalidWindow { preflight_id: String },
104
105 #[error("topology preflight hash drifted from {expected} to {actual}")]
106 TopologyPreflightHashMismatch { expected: String, actual: String },
107
108 #[error("topology preflight targets do not match selected plan targets")]
109 TopologyPreflightTargetsMismatch,
110
111 #[error("quiescence preflight policy does not match plan")]
112 QuiescencePolicyMismatch,
113
114 #[error("quiescence preflight was not accepted")]
115 QuiescencePreflightRejected,
116
117 #[error("quiescence preflight targets do not match selected plan targets")]
118 QuiescencePreflightTargetsMismatch,
119
120 #[error("operation {operation_id} targets unknown canister {target_canister_id}")]
121 UnknownOperationTarget {
122 operation_id: String,
123 target_canister_id: String,
124 },
125
126 #[error("backup selector {0} did not match a live topology node")]
127 UnknownSelector(String),
128
129 #[error("backup selector {selector} matched multiple canisters: {matches:?}")]
130 AmbiguousSelector {
131 selector: String,
132 matches: Vec<String>,
133 },
134
135 #[error("required preflight operation {0} is missing")]
136 MissingPreflight(&'static str),
137
138 #[error("mutating operation {operation_id} appears before required preflights")]
139 MutationBeforePreflight { operation_id: String },
140
141 #[error(transparent)]
142 Discovery(#[from] DiscoveryError),
143}