fraiseql_error/file.rs
1/// Errors that occur during file upload, validation, storage, or retrieval.
2#[derive(Debug, thiserror::Error)]
3pub enum FileError {
4 /// The uploaded file exceeds the configured maximum size.
5 #[error("File too large: {size} bytes (max: {max} bytes)")]
6 TooLarge {
7 /// Actual size of the uploaded file in bytes.
8 size: usize,
9 /// Maximum allowed file size in bytes.
10 max: usize,
11 },
12
13 /// The file's extension or declared MIME type is not on the allow-list.
14 #[error("Invalid file type: {got} (allowed: {allowed:?})")]
15 InvalidType {
16 /// The MIME type or extension that was supplied.
17 got: String,
18 /// The set of allowed MIME types or extensions.
19 allowed: Vec<String>,
20 },
21
22 /// The file's declared MIME type does not match its detected MIME type.
23 ///
24 /// This can indicate a spoofed `Content-Type` header.
25 #[error("MIME type mismatch: declared {declared}, detected {detected}")]
26 MimeMismatch {
27 /// The MIME type stated by the client.
28 declared: String,
29 /// The MIME type detected by content inspection.
30 detected: String,
31 },
32
33 /// An error occurred while writing to or reading from the backing storage
34 /// system (e.g. local disk, object store).
35 #[error("Storage error: {message}")]
36 Storage {
37 /// Description of the storage failure.
38 message: String,
39 /// Optional chained error from the storage backend.
40 #[source]
41 source: Option<Box<dyn std::error::Error + Send + Sync>>,
42 },
43
44 /// An error occurred while processing the file contents (e.g. image
45 /// resizing, format conversion).
46 #[error("Processing error: {message}")]
47 Processing {
48 /// Description of the processing failure.
49 message: String,
50 },
51
52 /// The requested file does not exist in the storage backend.
53 #[error("File not found: {id}")]
54 NotFound {
55 /// Identifier of the file that was not found.
56 id: String,
57 },
58
59 /// A virus or malware scanner flagged the uploaded file.
60 #[error("Virus detected: {details}")]
61 VirusDetected {
62 /// Scanner-provided details about the detected threat (server-side only).
63 details: String,
64 },
65
66 /// The user or tenant has exhausted their file storage quota.
67 #[error("Upload quota exceeded")]
68 QuotaExceeded,
69}
70
71impl FileError {
72 /// Returns a short, stable error code string suitable for API responses and
73 /// structured logging.
74 pub const fn error_code(&self) -> &'static str {
75 match self {
76 Self::TooLarge { .. } => "file_too_large",
77 Self::InvalidType { .. } => "file_invalid_type",
78 Self::MimeMismatch { .. } => "file_mime_mismatch",
79 Self::Storage { .. } => "file_storage_error",
80 Self::Processing { .. } => "file_processing_error",
81 Self::NotFound { .. } => "file_not_found",
82 Self::VirusDetected { .. } => "file_virus_detected",
83 Self::QuotaExceeded => "file_quota_exceeded",
84 }
85 }
86}