Skip to main content

canic_backup/persistence/
error.rs

1//! Module: persistence::error
2//!
3//! Responsibility: define typed persistence and integrity failures.
4//! Does not own: filesystem operations, JSON encoding, or checksum calculation.
5//! Boundary: aggregates lower-layer errors returned by persistence APIs.
6
7use crate::{
8    artifacts::ArtifactChecksumError, execution::BackupExecutionJournalError,
9    journal::JournalValidationError, manifest::ManifestValidationError, plan::BackupPlanError,
10};
11
12use std::io;
13
14use thiserror::Error as ThisError;
15
16///
17/// PersistenceError
18///
19/// Typed persistence and integrity failure for backup layout operations.
20/// Owned by persistence and returned by backup file IO and verification APIs.
21///
22
23#[derive(Debug, ThisError)]
24pub enum PersistenceError {
25    #[error("artifact path escapes backup root: {artifact_path}")]
26    ArtifactPathEscapesBackup { artifact_path: String },
27
28    #[error("manifest backup id {manifest} does not match journal backup id {journal}")]
29    BackupIdMismatch { manifest: String, journal: String },
30
31    #[error(transparent)]
32    Checksum(#[from] ArtifactChecksumError),
33
34    #[error("backup execution operation {sequence} is {state} but has no matching receipt")]
35    ExecutionOperationMissingReceipt { sequence: usize, state: String },
36
37    #[error("backup execution operation {sequence} timestamp does not match latest receipt")]
38    ExecutionOperationReceiptTimestampMismatch { sequence: usize },
39
40    #[error(transparent)]
41    InvalidBackupPlan(#[from] BackupPlanError),
42
43    #[error(transparent)]
44    InvalidExecutionJournal(#[from] BackupExecutionJournalError),
45
46    #[error(transparent)]
47    InvalidJournal(#[from] JournalValidationError),
48
49    #[error(transparent)]
50    InvalidManifest(#[from] ManifestValidationError),
51
52    #[error(transparent)]
53    Io(#[from] io::Error),
54
55    #[error(transparent)]
56    Json(#[from] serde_json::Error),
57
58    #[error("manifest topology receipt {field} does not match journal topology receipt")]
59    ManifestJournalTopologyReceiptMismatch {
60        field: String,
61        manifest: String,
62        journal: Option<String>,
63    },
64
65    #[error(
66        "manifest artifact path for {canister_id} snapshot {snapshot_id} does not match journal artifact path"
67    )]
68    ManifestJournalArtifactPathMismatch {
69        canister_id: String,
70        snapshot_id: String,
71        manifest: String,
72        journal: String,
73    },
74
75    #[error(
76        "manifest checksum for {canister_id} snapshot {snapshot_id} does not match journal checksum"
77    )]
78    ManifestJournalChecksumMismatch {
79        canister_id: String,
80        snapshot_id: String,
81        manifest: String,
82        journal: String,
83    },
84
85    #[error("artifact path does not exist: {0}")]
86    MissingArtifact(String),
87
88    #[error("manifest member {canister_id} snapshot {snapshot_id} has no journal artifact")]
89    MissingJournalArtifact {
90        canister_id: String,
91        snapshot_id: String,
92    },
93
94    #[error("journal artifact {canister_id} snapshot {snapshot_id} has no checksum")]
95    MissingJournalArtifactChecksum {
96        canister_id: String,
97        snapshot_id: String,
98    },
99
100    #[error("journal artifact {canister_id} snapshot {snapshot_id} is not durable")]
101    NonDurableArtifact {
102        canister_id: String,
103        snapshot_id: String,
104    },
105
106    #[error("backup plan {field} does not match execution journal")]
107    PlanJournalMismatch {
108        field: &'static str,
109        plan: String,
110        journal: String,
111    },
112
113    #[error("backup plan operation {sequence} {field} does not match execution journal")]
114    PlanJournalOperationMismatch {
115        sequence: usize,
116        field: &'static str,
117        plan: String,
118        journal: String,
119    },
120
121    #[error("journal artifact {canister_id} snapshot {snapshot_id} is not declared in manifest")]
122    UnexpectedJournalArtifact {
123        canister_id: String,
124        snapshot_id: String,
125    },
126}