Skip to main content

objects/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Shared error types across Heddle crates.
3
4use crate::object::{ChangeId, ContentHash, TreeError};
5
6/// Error type for repository/storage-adjacent operations.
7#[derive(Debug, thiserror::Error)]
8pub enum HeddleError {
9    #[error("object not found: {0}")]
10    NotFound(String),
11    #[error("state not found: {0}")]
12    StateNotFound(ChangeId),
13    #[error("invalid object: {0}")]
14    InvalidObject(String),
15    #[error("repository not found at {0}")]
16    RepositoryNotFound(std::path::PathBuf),
17    #[error("repository already exists at {0}")]
18    RepositoryExists(std::path::PathBuf),
19    #[error(
20        "repository config at {path} uses repository format {found} but this binary supports {supported}; upgrade heddle or run `heddle migrate`"
21    )]
22    RepositoryFormatTooNew {
23        path: std::path::PathBuf,
24        found: u32,
25        supported: u32,
26    },
27    #[error("io error: {0}")]
28    Io(#[from] std::io::Error),
29    #[error("serialization error: {0}")]
30    Serialization(String),
31    #[error("configuration error: {0}")]
32    Config(String),
33    #[error("configuration parse error at {path}: {source}")]
34    ConfigParse {
35        path: std::path::PathBuf,
36        // Keep the original `toml::de::Error` as the error source — not a
37        // flattened string — so `HeddleExitCode::from_error` can still
38        // downcast through the chain and classify config-parse failures as
39        // EX_DATAERR (65) rather than falling through to EX_IOERR (74).
40        #[source]
41        source: toml::de::Error,
42    },
43    #[error("conflict: {0}")]
44    Conflict(String),
45    #[error("compression error: {0}")]
46    Compression(String),
47    #[error("invalid ref name: {0}")]
48    InvalidRefName(String),
49    #[error("file too large: {0} bytes")]
50    InvalidFileSize(u64),
51    #[error("symlink target escapes repository: {0}")]
52    InvalidSymlinkTarget(std::path::PathBuf),
53    #[error("object corruption: expected {expected}, found {found}")]
54    Corruption {
55        expected: ContentHash,
56        found: ContentHash,
57    },
58    #[error(
59        "missing {object_type} object: {id} (run `heddle fsck --full` to inspect store integrity)"
60    )]
61    MissingObject { object_type: String, id: String },
62    #[error("invalid tree entry: {0}")]
63    InvalidTreeEntry(#[from] TreeError),
64}
65
66impl From<rmp_serde::encode::Error> for HeddleError {
67    fn from(e: rmp_serde::encode::Error) -> Self {
68        HeddleError::Serialization(e.to_string())
69    }
70}
71
72impl From<rmp_serde::decode::Error> for HeddleError {
73    fn from(e: rmp_serde::decode::Error) -> Self {
74        HeddleError::Serialization(e.to_string())
75    }
76}
77
78impl From<toml::de::Error> for HeddleError {
79    fn from(e: toml::de::Error) -> Self {
80        HeddleError::Config(e.to_string())
81    }
82}
83
84impl From<toml::ser::Error> for HeddleError {
85    fn from(e: toml::ser::Error) -> Self {
86        HeddleError::Config(e.to_string())
87    }
88}
89
90impl From<serde_json::Error> for HeddleError {
91    fn from(e: serde_json::Error) -> Self {
92        HeddleError::Serialization(e.to_string())
93    }
94}
95
96/// Result type for repository/storage-adjacent operations.
97pub type Result<T> = std::result::Result<T, HeddleError>;