canic_backup/persistence/
error.rs1use crate::{
8 artifacts::ArtifactChecksumError,
9 execution::BackupExecutionJournalError,
10 journal::{ArtifactState, JournalValidationError},
11 manifest::ManifestValidationError,
12 plan::BackupPlanError,
13};
14
15use std::io;
16
17use thiserror::Error as ThisError;
18
19#[derive(Debug, ThisError)]
27pub enum PersistenceError {
28 #[error("restore reference conflicts with retained recovery authority: {path}")]
29 RestoreReferenceConflict { path: String },
30
31 #[error("invalid restore reference record: {path}")]
32 InvalidRestoreReferences { path: String },
33
34 #[error(
35 "artifact commit paths must be distinct siblings: temporary={temporary}, canonical={canonical}"
36 )]
37 ArtifactCommitPathMismatch {
38 temporary: String,
39 canonical: String,
40 },
41
42 #[error(
43 "artifact commit found both temporary and canonical directories: temporary={temporary}, canonical={canonical}"
44 )]
45 ArtifactCommitPathConflict {
46 temporary: String,
47 canonical: String,
48 },
49
50 #[error(
51 "artifact commit found neither temporary nor canonical directory: temporary={temporary}, canonical={canonical}"
52 )]
53 ArtifactCommitPathMissing {
54 temporary: String,
55 canonical: String,
56 },
57
58 #[error("durable artifact directory publication is unsupported on platform {platform}")]
59 ArtifactCommitUnsupportedPlatform { platform: &'static str },
60
61 #[error("artifact path escapes backup root: {artifact_path}")]
62 ArtifactPathEscapesBackup { artifact_path: String },
63
64 #[error("manifest backup id {manifest} does not match journal backup id {journal}")]
65 BackupIdMismatch { manifest: String, journal: String },
66
67 #[error(transparent)]
68 Checksum(#[from] ArtifactChecksumError),
69
70 #[error("backup execution operation {sequence} is {state} but has no matching receipt")]
71 ExecutionOperationMissingReceipt { sequence: usize, state: String },
72
73 #[error("backup execution operation {sequence} timestamp does not match latest receipt")]
74 ExecutionOperationReceiptTimestampMismatch { sequence: usize },
75
76 #[error(transparent)]
77 InvalidBackupPlan(#[from] BackupPlanError),
78
79 #[error(transparent)]
80 InvalidExecutionJournal(#[from] BackupExecutionJournalError),
81
82 #[error(transparent)]
83 InvalidJournal(#[from] JournalValidationError),
84
85 #[error(transparent)]
86 InvalidManifest(#[from] ManifestValidationError),
87
88 #[error(transparent)]
89 Io(#[from] io::Error),
90
91 #[error(transparent)]
92 Json(#[from] serde_json::Error),
93
94 #[error("manifest topology receipt {field} does not match journal topology receipt")]
95 ManifestJournalTopologyReceiptMismatch {
96 field: String,
97 manifest: String,
98 journal: String,
99 },
100
101 #[error("backup manifest conflicts with the existing canonical manifest: {path}")]
102 ManifestConflict { path: String },
103
104 #[error(
105 "manifest artifact path for {canister_id} snapshot {snapshot_id} does not match journal artifact path"
106 )]
107 ManifestJournalArtifactPathMismatch {
108 canister_id: String,
109 snapshot_id: String,
110 manifest: String,
111 journal: String,
112 },
113
114 #[error(
115 "manifest checksum for {canister_id} snapshot {snapshot_id} does not match journal checksum"
116 )]
117 ManifestJournalChecksumMismatch {
118 canister_id: String,
119 snapshot_id: String,
120 manifest: String,
121 journal: String,
122 },
123
124 #[error("artifact path does not exist: {0}")]
125 MissingArtifact(String),
126
127 #[error("manifest member {canister_id} snapshot {snapshot_id} has no journal artifact")]
128 MissingJournalArtifact {
129 canister_id: String,
130 snapshot_id: String,
131 },
132
133 #[error("journal artifact {canister_id} snapshot {snapshot_id} has no checksum")]
134 MissingJournalArtifactChecksum {
135 canister_id: String,
136 snapshot_id: String,
137 },
138
139 #[error(
140 "journal artifact {canister_id} snapshot {snapshot_id} must be checksum verified before durable publication; found {state:?}"
141 )]
142 ArtifactNotChecksumVerified {
143 canister_id: String,
144 snapshot_id: String,
145 state: ArtifactState,
146 },
147
148 #[error("journal artifact {canister_id} snapshot {snapshot_id} is not durable")]
149 NonDurableArtifact {
150 canister_id: String,
151 snapshot_id: String,
152 },
153
154 #[error("backup plan {field} does not match execution journal")]
155 PlanJournalMismatch {
156 field: &'static str,
157 plan: String,
158 journal: String,
159 },
160
161 #[error("backup plan operation {sequence} {field} does not match execution journal")]
162 PlanJournalOperationMismatch {
163 sequence: usize,
164 field: &'static str,
165 plan: String,
166 journal: String,
167 },
168
169 #[error("journal artifact {canister_id} snapshot {snapshot_id} is not declared in manifest")]
170 UnexpectedJournalArtifact {
171 canister_id: String,
172 snapshot_id: String,
173 },
174
175 #[error("unsupported artifact filesystem entry at {path}: {kind}")]
176 UnsupportedArtifactEntry { path: String, kind: String },
177}