1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Error types with stable, FFI-friendly discriminant codes.
use std::path::PathBuf;
/// Stable, FFI-friendly discriminant for [`Error`].
///
/// The numeric values are part of the public contract once 1.0 is reached:
/// language bindings map errors to these codes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
#[non_exhaustive]
pub enum ErrorKind {
/// The registry lock could not be acquired within the timeout.
RegistryBusy = 2,
/// A model matching the query/spec was not found.
NotFound = 3,
/// `registry.json` exists but could not be parsed.
RegistryCorrupt = 4,
/// The registry was written by a newer, unsupported schema version.
UnsupportedSchema = 5,
/// A model spec string could not be parsed.
InvalidSpec = 6,
/// A network or remote-API failure.
Network = 7,
/// Downloaded or scanned content did not match the expected hash.
HashMismatch = 8,
/// An operation was refused for safety reasons (see message).
Refused = 9,
/// An underlying filesystem error.
Io = 10,
/// Anything else.
Other = 1,
}
/// The error type returned by all fallible modelshelf operations.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
/// The registry lock could not be acquired within the configured timeout.
#[error("registry is busy: could not acquire lock on {path} within {timeout_ms} ms")]
RegistryBusy {
/// Path of the lock file.
path: PathBuf,
/// How long we waited.
timeout_ms: u64,
},
/// `registry.json` exists but could not be parsed. The corrupt file has
/// been preserved at `quarantined_to`; the registry is NOT rebuilt
/// automatically.
#[error("registry file {path} is corrupt (preserved at {quarantined_to}): {reason}")]
RegistryCorrupt {
/// Path of the unreadable registry file.
path: PathBuf,
/// Where the corrupt copy was preserved.
quarantined_to: PathBuf,
/// Parser error message.
reason: String,
},
/// The registry was written by a newer schema version than this build
/// understands. Refusing to touch it protects the newer writer's data.
#[error("registry schema version {found} is newer than supported version {supported}")]
UnsupportedSchema {
/// Version found on disk.
found: u64,
/// Highest version this build supports.
supported: u64,
},
/// No model matched the given id, query, or spec.
#[error("model not found: {0}")]
NotFound(String),
/// A model spec string (e.g. `hf:org/repo/file.gguf`) could not be parsed.
#[error("invalid model spec: {0}")]
InvalidSpec(String),
/// A network or remote-API failure.
#[error("network error: {0}")]
Network(String),
/// Content hash verification failed.
#[error("hash mismatch: expected {expected}, got {actual}")]
HashMismatch {
/// The hash we expected.
expected: String,
/// The hash we computed.
actual: String,
},
/// The operation was refused for safety reasons.
#[error("refused: {0}")]
Refused(String),
/// An underlying filesystem error, annotated with the path involved.
#[error("I/O error at {path}: {source}")]
Io {
/// The path the operation was acting on.
path: PathBuf,
/// The underlying error.
#[source]
source: std::io::Error,
},
}
impl Error {
/// The stable [`ErrorKind`] code for this error.
pub fn kind(&self) -> ErrorKind {
match self {
Error::RegistryBusy { .. } => ErrorKind::RegistryBusy,
Error::RegistryCorrupt { .. } => ErrorKind::RegistryCorrupt,
Error::UnsupportedSchema { .. } => ErrorKind::UnsupportedSchema,
Error::NotFound(_) => ErrorKind::NotFound,
Error::InvalidSpec(_) => ErrorKind::InvalidSpec,
Error::Network(_) => ErrorKind::Network,
Error::HashMismatch { .. } => ErrorKind::HashMismatch,
Error::Refused(_) => ErrorKind::Refused,
Error::Io { .. } => ErrorKind::Io,
}
}
pub(crate) fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
Error::Io {
path: path.into(),
source,
}
}
}
/// Convenience alias used across the crate.
pub type Result<T> = std::result::Result<T, Error>;