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