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