worker/
error.rs

1use crate::kv::KvError;
2use wasm_bindgen::{JsCast, JsValue};
3
4/// All possible Error variants that might be encountered while working with a Worker.
5#[derive(Debug)]
6#[non_exhaustive]
7pub enum Error {
8    BadEncoding,
9    BodyUsed,
10    Json((String, u16)),
11    JsError(String),
12    #[cfg(feature = "http")]
13    Http(http::Error),
14    Infallible,
15    Internal(JsValue),
16    Io(std::io::Error),
17    BindingError(String),
18    RouteInsertError(matchit::InsertError),
19    RouteNoDataError,
20    RustError(String),
21    SerdeJsonError(serde_json::Error),
22    SerdeWasmBindgenError(serde_wasm_bindgen::Error),
23    #[cfg(feature = "http")]
24    StatusCode(http::status::InvalidStatusCode),
25    #[cfg(feature = "d1")]
26    D1(crate::d1::D1Error),
27    Utf8Error(std::str::Utf8Error),
28    #[cfg(feature = "timezone")]
29    TimezoneError,
30    KvError(KvError),
31}
32
33unsafe impl Sync for Error {}
34unsafe impl Send for Error {}
35
36#[cfg(feature = "http")]
37impl From<http::Error> for Error {
38    fn from(value: http::Error) -> Self {
39        Self::Http(value)
40    }
41}
42
43#[cfg(feature = "http")]
44impl From<http::status::InvalidStatusCode> for Error {
45    fn from(value: http::status::InvalidStatusCode) -> Self {
46        Self::StatusCode(value)
47    }
48}
49
50#[cfg(feature = "http")]
51impl From<http::header::InvalidHeaderName> for Error {
52    fn from(value: http::header::InvalidHeaderName) -> Self {
53        Self::RustError(format!("Invalid header name: {value:?}"))
54    }
55}
56
57#[cfg(feature = "http")]
58impl From<http::header::InvalidHeaderValue> for Error {
59    fn from(value: http::header::InvalidHeaderValue) -> Self {
60        Self::RustError(format!("Invalid header value: {value:?}"))
61    }
62}
63
64#[cfg(feature = "timezone")]
65impl From<chrono_tz::ParseError> for Error {
66    fn from(_value: chrono_tz::ParseError) -> Self {
67        Self::RustError("Invalid timezone".to_string())
68    }
69}
70
71impl From<std::str::Utf8Error> for Error {
72    fn from(value: std::str::Utf8Error) -> Self {
73        Self::Utf8Error(value)
74    }
75}
76
77impl From<core::convert::Infallible> for Error {
78    fn from(_value: core::convert::Infallible) -> Self {
79        Error::Infallible
80    }
81}
82
83impl From<KvError> for Error {
84    fn from(e: KvError) -> Self {
85        Self::KvError(e)
86    }
87}
88
89impl From<url::ParseError> for Error {
90    fn from(e: url::ParseError) -> Self {
91        Self::RustError(e.to_string())
92    }
93}
94
95impl From<serde_urlencoded::de::Error> for Error {
96    fn from(e: serde_urlencoded::de::Error) -> Self {
97        Self::RustError(e.to_string())
98    }
99}
100
101impl From<serde_wasm_bindgen::Error> for Error {
102    fn from(e: serde_wasm_bindgen::Error) -> Self {
103        let val: JsValue = e.into();
104        val.into()
105    }
106}
107
108#[cfg(feature = "d1")]
109impl From<crate::d1::D1Error> for Error {
110    fn from(e: crate::d1::D1Error) -> Self {
111        Self::D1(e)
112    }
113}
114
115impl std::fmt::Display for Error {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        match self {
118            Error::BadEncoding => write!(f, "content-type mismatch"),
119            Error::BodyUsed => write!(f, "body has already been read"),
120            Error::Json((msg, status)) => write!(f, "{msg} (status: {status})"),
121            Error::JsError(s) | Error::RustError(s) => {
122                write!(f, "{s}")
123            }
124            #[cfg(feature = "http")]
125            Error::Http(e) => write!(f, "http::Error: {e}"),
126            Error::Infallible => write!(f, "infallible"),
127            Error::Internal(_) => write!(f, "unrecognized JavaScript object"),
128            Error::Io(e) => write!(f, "IO Error: {e}"),
129            Error::BindingError(name) => write!(f, "no binding found for `{name}`"),
130            Error::RouteInsertError(e) => write!(f, "failed to insert route: {e}"),
131            Error::RouteNoDataError => write!(f, "route has no corresponding shared data"),
132            Error::SerdeJsonError(e) => write!(f, "Serde Error: {e}"),
133            Error::SerdeWasmBindgenError(e) => write!(f, "Serde Error: {e}"),
134            #[cfg(feature = "http")]
135            Error::StatusCode(e) => write!(f, "{e}"),
136            #[cfg(feature = "d1")]
137            Error::D1(e) => write!(f, "D1: {e:#?}"),
138            Error::Utf8Error(e) => write!(f, "{e}"),
139            #[cfg(feature = "timezone")]
140            Error::TimezoneError => write!(f, "Timezone Error"),
141            Error::KvError(KvError::JavaScript(s)) => write!(f, "js error: {s:?}"),
142            Error::KvError(KvError::Serialization(s)) => {
143                write!(f, "unable to serialize/deserialize: {s}")
144            }
145            Error::KvError(KvError::InvalidKvStore(s)) => write!(f, "invalid kv store: {s}"),
146        }
147    }
148}
149
150impl std::error::Error for Error {}
151
152// Not sure if the changes I've made here are good or bad...
153impl From<JsValue> for Error {
154    fn from(v: JsValue) -> Self {
155        match v.as_string().or_else(|| {
156            v.dyn_ref::<js_sys::Error>().map(|e| {
157                format!(
158                    "Error: {} - Cause: {}",
159                    e.to_string(),
160                    e.cause()
161                        .as_string()
162                        .or_else(|| { Some(e.to_string().into()) })
163                        .unwrap_or(String::from("N/A"))
164                )
165            })
166        }) {
167            Some(s) => Self::JsError(s),
168            None => Self::Internal(v),
169        }
170    }
171}
172
173impl From<std::io::Error> for Error {
174    fn from(error: std::io::Error) -> Self {
175        Self::Io(error)
176    }
177}
178
179impl From<Error> for JsValue {
180    fn from(e: Error) -> Self {
181        JsValue::from_str(&e.to_string())
182    }
183}
184
185impl From<&str> for Error {
186    fn from(a: &str) -> Self {
187        Error::RustError(a.to_string())
188    }
189}
190
191impl From<String> for Error {
192    fn from(a: String) -> Self {
193        Error::RustError(a)
194    }
195}
196
197impl From<matchit::InsertError> for Error {
198    fn from(e: matchit::InsertError) -> Self {
199        Error::RouteInsertError(e)
200    }
201}
202
203impl From<serde_json::Error> for Error {
204    fn from(e: serde_json::Error) -> Self {
205        Error::SerdeJsonError(e)
206    }
207}