objstore_r/error.rs
1// Author: spicyzhug@gmail.com
2// Copyright: lituus-io, all rights reserved
3//
4//! Errors.
5
6/// Result alias.
7pub type Result<T, E = Error> = std::result::Result<T, E>;
8
9/// Everything an object store can report.
10#[derive(Debug, thiserror::Error)]
11#[non_exhaustive]
12pub enum Error {
13 /// The object does not exist (ranged reads only; `get`/`head` return `None`).
14 #[error("object not found")]
15 NotFound,
16 /// A [`Cond::CreateOnly`](crate::Cond::CreateOnly) write found an existing object.
17 #[error("object already exists")]
18 Conflict,
19 /// A [`Cond::IfGeneration`](crate::Cond::IfGeneration) write found another
20 /// generation (or no object).
21 #[error("generation precondition failed")]
22 PreconditionFailed,
23 /// The key or prefix is not valid (see [`Key::parse`](crate::Key::parse)).
24 #[error("invalid key: {reason}")]
25 InvalidKey {
26 /// Why.
27 reason: &'static str,
28 },
29 /// The store could not be reached or refused for a transient reason.
30 #[error("store unavailable: {message}")]
31 Unavailable {
32 /// What happened (never contains credentials).
33 message: String,
34 /// Worth retrying.
35 retriable: bool,
36 },
37 /// Authentication or authorization failed.
38 #[error("not authorized: {message}")]
39 Auth {
40 /// What happened (never contains credentials).
41 message: String,
42 },
43 /// The body exceeds a configured limit.
44 #[error("object larger than the {limit}-byte limit")]
45 TooLarge {
46 /// The limit.
47 limit: u64,
48 },
49 /// The store answered with something unexpected.
50 #[error("protocol error: {message}")]
51 Protocol {
52 /// What was wrong.
53 message: String,
54 },
55 /// A fenced publish lost to another writer (see [`crate::fenced`]).
56 /// Stop writing; re-read before publishing again.
57 #[error("fenced: {reason}")]
58 Fenced {
59 /// Why.
60 reason: &'static str,
61 },
62 /// Published data failed verification against the record naming it.
63 #[error("corrupt: {message}")]
64 Corrupt {
65 /// What was wrong.
66 message: String,
67 },
68 /// Local I/O.
69 #[error("i/o: {source}")]
70 Io {
71 /// The underlying error.
72 #[from]
73 source: std::io::Error,
74 },
75 // New variants go last: a variant's position is its discriminant.
76 /// A ranged read of an object stored with a content encoding: a byte
77 /// range of an encoded (compressed) stream is meaningless. Read it whole
78 /// with `get`, which decodes it.
79 #[error("ranged read of a {encoding}-encoded object: read it whole")]
80 EncodedRange {
81 /// The object's `Content-Encoding`.
82 encoding: String,
83 },
84 /// A content encoding this build cannot write or decode (an unknown
85 /// token, or `gzip` without feature `gzip`).
86 #[error("unsupported content encoding {encoding:?}")]
87 UnsupportedEncoding {
88 /// The encoding named (at most 64 characters).
89 encoding: String,
90 },
91 /// The object was replaced or deleted while a read that had to resume
92 /// was in flight. Nothing from either generation is returned (two
93 /// generations are never spliced); read it again.
94 #[error("object replaced during a resumed read")]
95 Changed,
96 /// A request refused by the transport's request policy before any byte
97 /// was sent (see `http::Client::with_policy`).
98 #[error("refused by policy: {0}")]
99 Policy(#[from] PolicyError),
100 /// Credential discovery found no credential it is allowed to use (for
101 /// example under `token::MetadataPolicy::Forbid` with no user
102 /// credentials), or an empty token was supplied. Nothing was contacted.
103 #[error("no credentials: {reason}")]
104 NoCredentials {
105 /// Why.
106 reason: &'static str,
107 },
108}
109
110/// Why a request policy refused a request. Never carries the URL's query
111/// string, a body or a token.
112#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
113#[non_exhaustive]
114pub enum PolicyError {
115 /// The method, scheme, host, port or path is not one the policy allows.
116 #[error("endpoint not allowed: {reason}")]
117 Endpoint {
118 /// Which rule refused it.
119 reason: &'static str,
120 },
121 /// The SQL text of a `BigQuery` query job was refused.
122 #[error("query not allowed: {reason}")]
123 Query {
124 /// Why (the policy's own wording).
125 reason: std::borrow::Cow<'static, str>,
126 },
127 /// A request to a `BigQuery` query endpoint whose SQL could not be
128 /// isolated for checking (unreadable body, non-query or legacy-SQL job,
129 /// or a field that changes what the SQL reads). Refused under every
130 /// policy, so no query reaches `BigQuery` unchecked.
131 #[error("query body not checkable: {reason}")]
132 UncheckableQuery {
133 /// What was wrong.
134 reason: &'static str,
135 },
136}
137
138impl Error {
139 /// Worth retrying (transient unavailability; never conflicts or preconditions).
140 #[must_use]
141 pub fn is_retriable(&self) -> bool {
142 matches!(self, Error::Unavailable { retriable: true, .. })
143 }
144
145 #[cfg_attr(not(any(feature = "gcs", test)), allow(dead_code))]
146 pub(crate) fn unavailable(message: impl Into<String>, retriable: bool) -> Self {
147 Error::Unavailable { message: message.into(), retriable }
148 }
149
150 pub(crate) fn corrupt(message: impl Into<String>) -> Self {
151 Error::Corrupt { message: message.into() }
152 }
153
154 #[cfg_attr(not(feature = "gcs"), allow(dead_code))]
155 pub(crate) fn protocol(message: impl Into<String>) -> Self {
156 Error::Protocol { message: message.into() }
157 }
158}