1use axum::{
4 extract::rejection::JsonRejection,
5 http::{
6 header::{InvalidHeaderName, InvalidHeaderValue},
7 method::InvalidMethod,
8 StatusCode,
9 },
10};
11use lettre::{address::AddressError, transport::smtp};
12
13use crate::{controller::ErrorDetail, depcheck, validation::ModelValidationErrors};
14
15impl From<serde_json::Error> for Error {
25 fn from(val: serde_json::Error) -> Self {
26 Self::JSON(val).bt()
27 }
28}
29
30#[derive(thiserror::Error, Debug)]
31pub enum Error {
32 #[error("{inner}\n{backtrace}")]
33 WithBacktrace {
34 inner: Box<Self>,
35 backtrace: Box<std::backtrace::Backtrace>,
36 },
37
38 #[error("{0}")]
39 Message(String),
40
41 #[error(
42 "error while running worker: no queue provider populated in context. Did you configure \
43 BackgroundQueue and connection details in `queue` in your config file?"
44 )]
45 QueueProviderMissing,
46
47 #[error("task not found: '{0}'")]
48 TaskNotFound(String),
49
50 #[error(transparent)]
51 Scheduler(#[from] crate::scheduler::Error),
52
53 #[error(transparent)]
54 Axum(#[from] axum::http::Error),
55
56 #[error(transparent)]
57 Tera(#[from] tera::Error),
58
59 #[error(transparent)]
60 JSON(serde_json::Error),
61
62 #[error(transparent)]
63 JsonRejection(#[from] JsonRejection),
64
65 #[error("cannot parse `{1}`: {0}")]
66 YAMLFile(#[source] serde_yaml::Error, String),
67
68 #[error(transparent)]
69 YAML(#[from] serde_yaml::Error),
70
71 #[error(transparent)]
72 EnvVar(#[from] std::env::VarError),
73
74 #[error("Error sending email: '{0}'")]
75 EmailSender(#[from] lettre::error::Error),
76
77 #[error("Error sending email (smtp): '{0}'")]
78 Smtp(#[from] smtp::Error),
79
80 #[error("Worker error: {0}")]
81 Worker(String),
82
83 #[error(transparent)]
84 IO(#[from] std::io::Error),
85
86 #[cfg(feature = "with-db")]
87 #[error(transparent)]
88 DB(#[from] sea_orm::DbErr),
89
90 #[error(transparent)]
91 ParseAddress(#[from] AddressError),
92
93 #[error("{0}")]
94 Hash(String),
95
96 #[error("{0}")]
98 Unauthorized(String),
99
100 #[error("not found")]
102 NotFound,
103
104 #[error("{0}")]
105 BadRequest(String),
106
107 #[error("")]
108 CustomError(StatusCode, ErrorDetail),
109
110 #[error("internal server error")]
111 InternalServerError,
112
113 #[error(transparent)]
114 InvalidHeaderValue(#[from] InvalidHeaderValue),
115
116 #[error(transparent)]
117 InvalidHeaderName(#[from] InvalidHeaderName),
118
119 #[error(transparent)]
120 InvalidMethod(#[from] InvalidMethod),
121
122 #[error(transparent)]
123 TaskJoinError(#[from] tokio::task::JoinError),
124
125 #[cfg(feature = "with-db")]
126 #[error(transparent)]
128 Model(#[from] crate::model::ModelError),
129
130 #[cfg(feature = "bg_redis")]
131 #[error(transparent)]
132 Redis(#[from] redis::RedisError),
133
134 #[cfg(any(feature = "bg_pg", feature = "bg_sqlt"))]
135 #[error(transparent)]
136 Sqlx(#[from] sqlx::Error),
137
138 #[error(transparent)]
139 Storage(#[from] crate::storage::StorageError),
140
141 #[error(transparent)]
142 Cache(#[from] crate::cache::CacheError),
143
144 #[cfg(debug_assertions)]
145 #[error(transparent)]
146 Generators(#[from] loco_gen::Error),
147
148 #[error(transparent)]
149 VersionCheck(#[from] depcheck::VersionCheckError),
150
151 #[error(transparent)]
152 SemVer(#[from] semver::Error),
153
154 #[error(transparent)]
155 Any(#[from] Box<dyn std::error::Error + Send + Sync>),
156
157 #[error(transparent)]
158 Validation(#[from] ModelValidationErrors),
159
160 #[error(transparent)]
161 AxumFormRejection(#[from] axum::extract::rejection::FormRejection),
162}
163
164impl Error {
165 pub fn wrap(err: impl std::error::Error + Send + Sync + 'static) -> Self {
166 Self::Any(Box::new(err)) }
168
169 pub fn msg(err: impl std::error::Error + Send + Sync + 'static) -> Self {
170 Self::Message(err.to_string()) }
172 #[must_use]
173 pub fn string(s: &str) -> Self {
174 Self::Message(s.to_string())
175 }
176 #[must_use]
177 pub fn bt(self) -> Self {
178 let backtrace = std::backtrace::Backtrace::capture();
179 match backtrace.status() {
180 std::backtrace::BacktraceStatus::Disabled
181 | std::backtrace::BacktraceStatus::Unsupported => self,
182 _ => Self::WithBacktrace {
183 inner: Box::new(self),
184 backtrace: Box::new(backtrace),
185 },
186 }
187 }
188}