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