backbone_bucket/error.rs
1//! Top-level error type for the bucket module.
2//!
3//! `BucketError` is the module's unified error surface — storage failures,
4//! authorization denials, config/signing issues, and missing objects all
5//! collapse into one enum so consumers get precise `match` coverage.
6//!
7//! Converts into `backbone_core::ServiceError` for compatibility with the
8//! framework error plumbing used by the generated CRUD stack.
9
10use std::io;
11
12use thiserror::Error;
13
14/// Unified error surface for storage, serving, and signing.
15#[derive(Debug, Error)]
16pub enum BucketError {
17 /// Object not found in storage or database.
18 #[error("not found")]
19 NotFound,
20
21 /// Caller is not permitted to perform the requested action.
22 #[error("forbidden")]
23 Forbidden,
24
25 /// Request could not be authenticated.
26 #[error("unauthenticated")]
27 Unauthenticated,
28
29 /// Presigned URL has expired or is malformed.
30 #[error("invalid or expired signature")]
31 InvalidSignature,
32
33 /// Configured backend cannot satisfy this operation (e.g. `public_url`
34 /// on a backend without a public bucket configured).
35 #[error("operation not supported by backend: {0}")]
36 Unsupported(String),
37
38 /// Missing or malformed configuration.
39 #[error("configuration error: {0}")]
40 Config(String),
41
42 /// Storage backend I/O error.
43 #[error("storage I/O error: {0}")]
44 Io(#[from] io::Error),
45
46 /// S3/MinIO-side error.
47 #[error("s3 error: {0}")]
48 S3(String),
49
50 /// URL construction / parsing error.
51 #[error("url error: {0}")]
52 Url(String),
53
54 /// Request payload is invalid (missing required fields, malformed
55 /// input). Maps to HTTP 400.
56 #[error("invalid input: {0}")]
57 InvalidInput(String),
58
59 /// Operation conflicts with current resource state (e.g. uploading
60 /// to a readonly/archived bucket). Maps to HTTP 409.
61 #[error("conflict: {0}")]
62 Conflict(String),
63
64 /// Payload exceeds the allowed size. Maps to HTTP 413.
65 #[error("payload too large: {0}")]
66 PayloadTooLarge(String),
67
68 /// MIME type is not in the bucket's allow-list. Maps to HTTP 415.
69 #[error("unsupported media type: {0}")]
70 UnsupportedMediaType(String),
71
72 /// Catch-all for errors outside the above categories.
73 #[error("{0}")]
74 Other(String),
75}
76
77pub type BucketResult<T> = Result<T, BucketError>;
78
79impl From<BucketError> for backbone_core::ServiceError {
80 fn from(err: BucketError) -> Self {
81 match err {
82 BucketError::NotFound => backbone_core::ServiceError::NotFound,
83 BucketError::Forbidden => {
84 backbone_core::ServiceError::Validation("forbidden".to_string())
85 }
86 BucketError::Unauthenticated => {
87 backbone_core::ServiceError::Validation("unauthenticated".to_string())
88 }
89 other => backbone_core::ServiceError::Internal(other.to_string()),
90 }
91 }
92}
93
94impl From<url::ParseError> for BucketError {
95 fn from(err: url::ParseError) -> Self {
96 BucketError::Url(err.to_string())
97 }
98}