Skip to main content

octocrab/
error.rs

1use http::uri::InvalidUri;
2
3use snafu::{Backtrace, Snafu};
4
5use std::fmt;
6use std::fmt::{Display, Formatter};
7use std::string::FromUtf8Error;
8use tower::BoxError;
9
10//This is workaround until I figure out how to get TryInto errors to work
11#[derive(Debug)]
12pub struct UriParseError;
13
14impl Display for UriParseError {
15    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
16        write!(f, "Failed to parse URI")
17    }
18}
19
20impl std::error::Error for UriParseError {}
21
22/// An error that could have occurred while using [`crate::Octocrab`].
23#[derive(Snafu, Debug)]
24#[snafu(visibility(pub))]
25#[non_exhaustive]
26pub enum Error {
27    GitHub {
28        source: Box<GitHubError>,
29        backtrace: Backtrace,
30    },
31    UriParse {
32        source: UriParseError,
33        backtrace: Backtrace,
34    },
35    Uri {
36        source: InvalidUri,
37        backtrace: Backtrace,
38    },
39    #[snafu(display("Installation Error: Github App authorization is required to target an installation.\n\nFound at {}", backtrace))]
40    Installation { backtrace: Backtrace },
41    #[snafu(display("Error getting installation access token: octocrab instance is not an installation.\n\nFound at {}", backtrace))]
42    InstallationTokenInvalidAuth { backtrace: Backtrace },
43    InvalidHeaderValue {
44        source: http::header::InvalidHeaderValue,
45        backtrace: Backtrace,
46    },
47
48    #[snafu(display("HTTP Error: {}\n\nFound at {}", source, backtrace))]
49    Http {
50        source: http::Error,
51        backtrace: Backtrace,
52    },
53
54    InvalidUtf8 {
55        source: FromUtf8Error,
56        backtrace: Backtrace,
57    },
58
59    Encoder {
60        source: std::io::Error,
61        backtrace: Backtrace,
62    },
63
64    #[snafu(display("Service Error: {}\n\nFound at {}", source, backtrace))]
65    Service {
66        source: BoxError,
67        backtrace: Backtrace,
68    },
69
70    #[snafu(display("Hyper Error: {}\n\nFound at {}", source, backtrace))]
71    Hyper {
72        source: hyper::Error,
73        backtrace: Backtrace,
74    },
75
76    #[snafu(display("Serde Url Encode Error: {}\nFound at {}", source, backtrace))]
77    SerdeUrlEncoded {
78        source: serde_urlencoded::ser::Error,
79        backtrace: Backtrace,
80    },
81
82    #[snafu(display("Serde Error: {}\nFound at {}", source, backtrace))]
83    Serde {
84        source: serde_json::Error,
85        backtrace: Backtrace,
86    },
87    #[snafu(display("JSON Error in {}: {}\nFound at {}", source.path(), source.inner(), backtrace))]
88    Json {
89        source: serde_path_to_error::Error<serde_json::Error>,
90        backtrace: Backtrace,
91    },
92    #[snafu(display("JWT Error in {}\nFound at {}", source, backtrace))]
93    JWT {
94        source: jsonwebtoken::errors::Error,
95        backtrace: Backtrace,
96    },
97    Other {
98        source: Box<dyn std::error::Error + Send + Sync>,
99        backtrace: Backtrace,
100    },
101}
102
103/// An error returned from GitHub's API.
104#[derive(Debug, Clone)]
105#[non_exhaustive]
106pub struct GitHubError {
107    pub documentation_url: Option<String>,
108    pub errors: Option<Vec<serde_json::Value>>,
109    pub message: String,
110    pub status_code: http::StatusCode,
111}
112
113impl fmt::Display for GitHubError {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        write!(f, "{}", self.message)?;
116
117        if let Some(documentation_url) = &self.documentation_url {
118            write!(f, "\nDocumentation URL: {documentation_url}")?;
119        }
120
121        if let Some(errors) = &self.errors.as_ref().filter(|errors| !errors.is_empty()) {
122            write!(f, "\nErrors:")?;
123            for error in errors.iter() {
124                write!(f, "\n- {error}")?;
125            }
126        }
127
128        Ok(())
129    }
130}
131
132impl std::error::Error for GitHubError {}