Skip to main content

tor_error/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3// @@ begin lint list maintained by maint/add_warning @@
4#![allow(renamed_and_removed_lints)] // @@REMOVE_WHEN(ci_arti_stable)
5#![allow(unknown_lints)] // @@REMOVE_WHEN(ci_arti_nightly)
6#![warn(missing_docs)]
7#![warn(noop_method_call)]
8#![warn(unreachable_pub)]
9#![warn(clippy::all)]
10#![deny(clippy::await_holding_lock)]
11#![deny(clippy::cargo_common_metadata)]
12#![deny(clippy::cast_lossless)]
13#![deny(clippy::checked_conversions)]
14#![warn(clippy::cognitive_complexity)]
15#![deny(clippy::debug_assert_with_mut_call)]
16#![deny(clippy::exhaustive_enums)]
17#![deny(clippy::exhaustive_structs)]
18#![deny(clippy::expl_impl_clone_on_copy)]
19#![deny(clippy::fallible_impl_from)]
20#![deny(clippy::implicit_clone)]
21#![deny(clippy::large_stack_arrays)]
22#![warn(clippy::manual_ok_or)]
23#![deny(clippy::missing_docs_in_private_items)]
24#![warn(clippy::needless_borrow)]
25#![warn(clippy::needless_pass_by_value)]
26#![warn(clippy::option_option)]
27#![deny(clippy::print_stderr)]
28#![deny(clippy::print_stdout)]
29#![warn(clippy::rc_buffer)]
30#![deny(clippy::ref_option_ref)]
31#![warn(clippy::semicolon_if_nothing_returned)]
32#![warn(clippy::trait_duplication_in_bounds)]
33#![deny(clippy::unchecked_time_subtraction)]
34#![deny(clippy::unnecessary_wraps)]
35#![warn(clippy::unseparated_literal_suffix)]
36#![deny(clippy::unwrap_used)]
37#![deny(clippy::mod_module_files)]
38#![allow(clippy::let_unit_value)] // This can reasonably be done for explicitness
39#![allow(clippy::uninlined_format_args)]
40#![allow(clippy::significant_drop_in_scrutinee)] // arti/-/merge_requests/588/#note_2812945
41#![allow(clippy::result_large_err)] // temporary workaround for arti#587
42#![allow(clippy::needless_raw_string_hashes)] // complained-about code is fine, often best
43#![allow(clippy::needless_lifetimes)] // See arti#1765
44#![allow(mismatched_lifetime_syntaxes)] // temporary workaround for arti#2060
45#![deny(clippy::unused_async)]
46//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
47
48use derive_more::Display;
49
50mod internal;
51pub use internal::*;
52
53mod report;
54pub use report::*;
55
56mod retriable;
57pub use retriable::*;
58
59mod misc;
60pub use misc::*;
61
62#[cfg(feature = "tracing")]
63pub mod tracing;
64
65#[cfg(feature = "http")]
66mod http;
67
68/// Classification of an error arising from Arti's Tor operations
69///
70/// This `ErrorKind` should suffice for programmatic handling by most applications embedding Arti:
71/// get the kind via [`HasKind::kind`] and compare it to the expected value(s) with equality
72/// or by matching.
73///
74/// When forwarding or reporting errors, use the whole error (e.g., `TorError`), not just the kind:
75/// the error itself will contain more detail and context which is useful to humans.
76//
77// Splitting vs lumping guidelines:
78//
79// # Split on the place which caused the error
80//
81// Every ErrorKind should generally have an associated "location" in
82// which it occurred.  If a problem can happen in two different
83// "locations", it should have two different ErrorKinds.  (This goal
84// may be frustrated sometimes by difficulty in determining where exactly
85// a given error occurred.)
86//
87// The location of an ErrorKind should always be clear from its name.  If is not
88// clear, add a location-related word to the name of the ErrorKind.
89//
90// For the purposes of this discussion, the following locations exist:
91//   - Process:  Our code, or the application code using it.  These errors don't
92//     usually need a special prefix.
93//   - Host: A problem with our local computing  environment.  These errors
94//     usually reflect trying to run under impossible circumstances (no file
95//     system, no permissions, etc).
96//   - Local: Another process on the same machine, or on the network between us
97//     and the Tor network.  Errors in this location often indicate an outage,
98//     misconfiguration, or a censorship event.
99//   - Tor: Anywhere within the Tor network, or connections between Tor relays.
100//     The words "Exit" and "Relay" also indicate this location.
101//   - Remote: Anywhere _beyond_ the Tor exit. Can be a problem in the Tor
102//     exit's connection to the real internet,  or with the remote host that the
103//     exit is talking to.  (This kind of error can also indicate that the exit
104//     is lying.)
105//
106// ## Lump any locations more fine-grained than that.
107//
108// We do not split locations more finely unless there's a good reason to do so.
109// For example, we don't typically split errors within the "Tor" location based
110// on whether they happened at a guard, a directory, or an exit.  (Errors with
111// "Exit" or "Guard" in their names are okay, so long as that kind of error can
112// _only_ occur at an Exit or Guard.)
113//
114// # Split based on reasonable response and semantics
115//
116// We also should split ErrorKinds based on what it's reasonable for the
117// receiver to do with them.  Users may find more applications for our errors
118// than we do, so we shouldn't assume that we can predict every reasonable use
119// in advance.
120//
121// ErrorKinds should be more specific than just the locations in which they
122// happen: for example, there shouldn't be a `TorNetworkError` or
123// a `RemoteFailure`.
124//
125// # Avoid exposing implementation details
126//
127// ErrorKinds should not relate to particular code paths in the Arti codebase.
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
130#[non_exhaustive]
131pub enum ErrorKind {
132    /// Error connecting to the Tor network
133    ///
134    /// Perhaps the local network is not working,
135    /// or perhaps the chosen relay or bridge is not working properly.
136    /// Not used for errors that occur within the Tor network, or accessing the public
137    /// internet on the far side of Tor.
138    #[display("error connecting to Tor")]
139    TorAccessFailed,
140
141    /// An attempt was made to use a Tor client for something without bootstrapping it first.
142    #[display("attempted to use unbootstrapped client")]
143    BootstrapRequired,
144
145    /// Our network directory has expired before we were able to replace it.
146    ///
147    /// This kind of error can indicate one of several possible problems:
148    /// * It can occur if the client used to be on the network, but has been
149    ///   unable to make directory connections for a while.
150    /// * It can occur if the client has been suspended or sleeping for a long
151    ///   time, and has suddenly woken up without having a chance to replace its
152    ///   network directory.
153    /// * It can happen if the client has a sudden clock jump.
154    ///
155    /// Often, retrying after a minute or so will resolve this issue.
156    ///
157    // TODO this is pretty shonky.  "try again after a minute or so", seriously?
158    //
159    /// Future versions of Arti may resolve this situation automatically without caller
160    /// intervention, possibly depending on preferences and API usage, in which case this kind of
161    /// error will never occur.
162    //
163    // TODO: We should distinguish among the actual issues here, and report a
164    // real bootstrapping problem when it exists.
165    #[display("network directory is expired.")]
166    DirectoryExpired,
167
168    /// IO error accessing local persistent state
169    ///
170    /// For example, the disk might be full, or there may be a permissions problem.
171    /// Usually the source will be [`std::io::Error`].
172    ///
173    /// Note that this kind of error only applies to problems in your `state_dir`:
174    /// problems with your cache are another kind.
175    #[display("could not read/write persistent state")]
176    PersistentStateAccessFailed,
177
178    /// We could not start up because a local resource is already being used by someone else
179    ///
180    /// Local resources include things like listening ports and state lockfiles.
181    /// (We don't use this error for "out of disk space" and the like.)
182    ///
183    /// This can occur when another process
184    /// (or another caller of Arti APIs)
185    /// is already running a facility that overlaps with the one being requested.
186    ///
187    /// For example,
188    /// running multiple processes each containing instances of the same hidden service,
189    /// using the same state directories etc., is not supported.
190    ///
191    /// Another example:
192    /// if Arti is configured to listen on a particular port,
193    /// but another process on the system is already listening there,
194    /// the resulting error has kind `LocalResourceAlreadyInUse`.
195    // Actually, we only currently listen on ports in `arti` so we don't return
196    // any Rust errors for this situation at all, at the time of writing.
197    #[display("local resource (port, lockfile, etc.) already in use")]
198    LocalResourceAlreadyInUse,
199
200    /// We encountered a problem with filesystem permissions.
201    ///
202    /// This is likeliest to be caused by permissions on a file or directory
203    /// being too permissive; the next likeliest cause is that we were unable to
204    /// check the permissions on the file or directory, or on one of its
205    /// ancestors.
206    #[display("problem with filesystem permissions")]
207    FsPermissions,
208
209    /// Tor client's persistent state has been corrupted
210    ///
211    /// This could be because of a bug in the Tor code, or because something
212    /// else has been messing with the data.
213    ///
214    /// This might also occur if the Tor code was upgraded and the new Tor is
215    /// not compatible.
216    ///
217    /// Note that this kind of error only applies to problems in your
218    /// `state_dir`: problems with your cache are another kind.
219    #[display("corrupted data in persistent state")]
220    PersistentStateCorrupted,
221
222    /// Tor client's cache has been corrupted.
223    ///
224    /// This could be because of a bug in the Tor code, or because something else has been messing
225    /// with the data.
226    ///
227    /// This might also occur if the Tor code was upgraded and the new Tor is not compatible.
228    ///
229    /// Note that this kind of error only applies to problems in your `cache_dir`:
230    /// problems with your persistent state are another kind.
231    #[display("corrupted data in cache")]
232    CacheCorrupted,
233
234    /// We had a problem reading or writing to our data cache.
235    ///
236    /// This may be a disk error, a file permission error, or similar.
237    ///
238    /// Note that this kind of error only applies to problems in your `cache_dir`:
239    /// problems with your persistent state are another kind.
240    #[display("cache access problem")]
241    CacheAccessFailed,
242
243    /// The keystore has been corrupted
244    ///
245    /// This could be because of a bug in the Tor code, or because something else has been messing
246    /// with the data.
247    ///
248    /// Note that this kind of error only applies to problems in your `keystore_dir`:
249    /// problems with your cache or persistent state are another kind.
250    #[display("corrupted data in keystore")]
251    KeystoreCorrupted,
252
253    /// IO error accessing keystore
254    ///
255    /// For example, the disk might be full, or there may be a permissions problem.
256    /// The source is typically an [`std::io::Error`].
257    ///
258    /// Note that this kind of error only applies to problems in your `keystore_dir`:
259    /// problems with your cache or persistent state are another kind.
260    #[display("could not access keystore")]
261    KeystoreAccessFailed,
262
263    /// Tor client's Rust async reactor is shutting down.
264    ///
265    /// This likely indicates that the reactor has encountered a fatal error, or
266    /// has been told to do a clean shutdown, and it isn't possible to spawn new
267    /// tasks.
268    #[display("reactor is shutting down")]
269    ReactorShuttingDown,
270
271    /// Tor client is shutting down.
272    ///
273    /// This likely indicates that the last handle to the `TorClient` has been
274    /// dropped, and is preventing other operations from completing.
275    #[display("Tor client is shutting down.")]
276    ArtiShuttingDown,
277
278    /// This Tor client software is missing some feature that is recommended
279    /// (or required) for operation on the network.
280    ///
281    /// This occurs when the directory authorities tell us that we ought to have
282    /// a particular protocol feature that we do not support.
283    /// The correct solution is likely to upgrade to a more recent version of Arti.
284    #[display("Software version is deprecated")]
285    SoftwareDeprecated,
286
287    /// An operation failed because we waited too long for an exit to do
288    /// something.
289    ///
290    /// This error can happen if the host you're trying to connect to isn't
291    /// responding to traffic.
292    /// It can also happen if an exit, or hidden service, is overloaded, and
293    /// unable to answer your replies in a timely manner.
294    ///
295    /// And it might simply mean that the Tor network itself
296    /// (including possibly relays, or hidden service introduction or rendezvous points)
297    /// is not working properly
298    ///
299    /// In either case, trying later, or on a different circuit, might help.
300    //
301    // TODO: Say that this is distinct from the case where the exit _tells you_
302    // that there is a timeout.
303    #[display("operation timed out at exit")]
304    RemoteNetworkTimeout,
305
306    /// One or more configuration values were invalid or incompatible.
307    ///
308    /// This kind of error can happen if the user provides an invalid or badly
309    /// formatted configuration file, if some of the options in that file are
310    /// out of their ranges or unparsable, or if the options are not all
311    /// compatible with one another. It can also happen if configuration options
312    /// provided via APIs are out of range.
313    ///
314    /// If this occurs because of user configuration, it's probably best to tell
315    /// the user about the error. If it occurs because of API usage, it's
316    /// probably best to fix the code that causes the error.
317    #[display("invalid configuration")]
318    InvalidConfig,
319
320    /// Tried to change the configuration of a running Arti service in a way
321    /// that isn't supported.
322    ///
323    /// This kind of error can happen when you call a `reconfigure()` method on
324    /// a service (or part of a service) and the new configuration is not
325    /// compatible with the previous configuration.
326    ///
327    /// The only available remedy is to tear down the service and make a fresh
328    /// one (for example, by making a new `TorClient`).
329    #[display("invalid configuration transition")]
330    InvalidConfigTransition,
331
332    /// Tried to look up a directory depending on the user's home directory, but
333    /// the user's home directory isn't set or can't be found.
334    ///
335    /// This kind of error can also occur if we're running in an environment
336    /// where users don't have home directories.
337    ///
338    /// To resolve this kind of error, either move to an OS with home
339    /// directories, or make sure that all paths in the configuration are set
340    /// explicitly, and do not depend on any path variables.
341    #[display("could not find a home directory")]
342    NoHomeDirectory,
343
344    /// A requested operation was not implemented by Arti.
345    ///
346    /// This kind of error can happen when requesting a piece of protocol
347    /// functionality that has not (yet) been implemented in the Arti project.
348    ///
349    /// If it happens as a result of a user activity, it's fine to ignore, log,
350    /// or report the error. If it happens as a result of direct API usage, it
351    /// may indicate that you're using something that isn't implemented yet.
352    ///
353    /// This kind can relate both to operations which we plan to implement, and
354    /// to operations which we do not.  It does not relate to facilities which
355    /// are disabled (e.g. at build time) or harmful.
356    ///
357    /// It can refer to facilities which were once implemented in Tor or Arti
358    /// but for which support has been removed.
359    #[display("operation not implemented")]
360    NotImplemented,
361
362    /// A feature was requested which has been disabled in this build of Arti.
363    ///
364    /// This kind of error happens when the running Arti was built without the
365    /// appropriate feature (usually, cargo feature) enabled.
366    ///
367    /// This might indicate that the overall running system has been
368    /// mis-configured at build-time.  Alternatively, it can occur if the
369    /// running system is deliberately stripped down, in which case it might be
370    /// reasonable to simply report this error to a user.
371    #[display("operation not supported because Arti feature disabled")]
372    FeatureDisabled,
373
374    /// Someone or something local violated a network protocol.
375    ///
376    /// This kind of error can happen when a local program accessing us over some
377    /// other protocol violates the protocol's requirements.
378    ///
379    /// This usually indicates a programming error: either in that program's
380    /// implementation of the protocol, or in ours.  In any case, the problem
381    /// is with software on the local system (or otherwise sharing a Tor client).
382    ///
383    /// It might also occur if the local system has an incompatible combination
384    /// of tools that we can't talk with.
385    ///
386    /// This error kind does *not* include situations that are better explained
387    /// by a local program simply crashing or terminating unexpectedly.
388    #[display("local protocol violation (local bug or incompatibility)")]
389    LocalProtocolViolation,
390
391    /// Someone or something on the Tor network violated the Tor protocols.
392    ///
393    /// This kind of error can happen when a remote Tor instance behaves in a
394    /// way we don't expect.
395    ///
396    /// It usually indicates a programming error: either in their implementation
397    /// of the protocol, or in ours.  It can also indicate an attempted attack,
398    /// though that can be hard to diagnose.
399    #[display("Tor network protocol violation (bug, incompatibility, or attack)")]
400    TorProtocolViolation,
401
402    /// Something went wrong with a network connection or the local network.
403    ///
404    /// This kind of error is usually safe to retry, and shouldn't typically be
405    /// seen.  By the time it reaches the caller, a more specific error type
406    /// should typically be available.
407    #[display("problem with network or connection")]
408    LocalNetworkError,
409
410    /// More of a local resource was needed, than is available (or than we are allowed)
411    ///
412    /// For example, we tried to use more memory than permitted by our memory quota.
413    #[display("local resource exhausted")]
414    LocalResourceExhausted,
415
416    /// A problem occurred when launching or communicating with an external
417    /// process running on this computer.
418    #[display("an externally launched plug-in tool failed")]
419    ExternalToolFailed,
420
421    /// A relay had an identity other than the one we expected.
422    ///
423    /// This could indicate a MITM attack, but more likely indicates that the
424    /// relay has changed its identity but the new identity hasn't propagated
425    /// through the directory system yet.
426    #[display("identity mismatch")]
427    RelayIdMismatch,
428
429    /// An attempt to do something remotely through the Tor network failed
430    /// because the circuit it was using shut down before the operation could
431    /// finish.
432    #[display("circuit collapsed")]
433    CircuitCollapse,
434
435    /// An operation timed out on the tor network.
436    ///
437    /// This may indicate a network problem, either with the local network
438    /// environment's ability to contact the Tor network, or with the Tor
439    /// network itself.
440    #[display("tor operation timed out")]
441    TorNetworkTimeout,
442
443    /// We tried but failed to download a piece of directory information.
444    ///
445    /// This is a lower-level kind of error; in general it should be retried
446    /// before the user can see it.   In the future it is likely to be split
447    /// into several other kinds.
448    // TODO ^
449    #[display("directory fetch attempt failed")]
450    TorDirectoryError,
451
452    /// An operation finished because a remote stream was closed successfully.
453    ///
454    /// This can indicate that the target server closed the TCP connection,
455    /// or that the exit told us that it closed the TCP connection.
456    /// Callers should generally treat this like a closed TCP connection.
457    #[display("remote stream closed")]
458    RemoteStreamClosed,
459
460    /// An operation finished because the remote stream was closed abruptly.
461    ///
462    /// This kind of error is analogous to an ECONNRESET error; it indicates
463    /// that the exit reported that the stream was terminated without a clean
464    /// TCP shutdown.
465    ///
466    /// For most purposes, it's fine to treat this kind of error the same as
467    /// regular unexpected close.
468    #[display("remote stream reset")]
469    RemoteStreamReset,
470
471    /// An operation finished because a remote stream was closed unsuccessfully.
472    ///
473    /// This indicates that the exit reported some error message for the stream.
474    ///
475    /// We only provide this error kind when no more specific kind is available.
476    #[display("remote stream error")]
477    RemoteStreamError,
478
479    /// A stream failed, and the exit reports that the remote host refused
480    /// the connection.
481    ///
482    /// This is analogous to an ECONNREFUSED error.
483    #[display("remote host refused connection")]
484    RemoteConnectionRefused,
485
486    /// A stream was rejected by the exit relay because of that relay's exit
487    /// policy.
488    ///
489    /// (In Tor, exits have a set of policies declaring which addresses and
490    /// ports they're willing to connect to.  Clients download only _summaries_
491    /// of these policies, so it's possible to be surprised by an exit's refusal
492    /// to connect somewhere.)
493    #[display("rejected by exit policy")]
494    ExitPolicyRejected,
495
496    /// An operation failed, and the exit reported that it waited too long for
497    /// the operation to finish.
498    ///
499    /// This kind of error is distinct from `RemoteNetworkTimeout`, which means
500    /// that _our own_ timeout threshold was violated.
501    #[display("timeout at exit relay")]
502    ExitTimeout,
503
504    /// An operation failed, and the exit reported a network failure of some
505    /// kind.
506    ///
507    /// This kind of error can occur for a number of reasons.  If it happens
508    /// when trying to open a stream, it usually indicates a problem connecting,
509    /// such as an ENOROUTE error.
510    #[display("network failure at exit")]
511    RemoteNetworkFailed,
512
513    /// An operation finished because an exit failed to look up a hostname.
514    ///
515    /// Unfortunately, the Tor protocol does not distinguish failure of DNS
516    /// services ("we couldn't find out if this host exists and what its name is")
517    /// from confirmed denials ("this is not a hostname").  So this kind
518    /// conflates both those sorts of error.
519    ///
520    /// Trying at another exit might succeed, or the address might truly be
521    /// unresolvable.
522    #[display("remote hostname not found")]
523    RemoteHostNotFound,
524
525    /// The target hidden service (`.onion` service) was not found in the directory
526    ///
527    /// We successfully connected to at least one directory server,
528    /// but it didn't have a record of the hidden service.
529    ///
530    /// This probably means that the hidden service is not running, or does not exist.
531    /// (It might mean that the directory servers are faulty,
532    /// and that the hidden service was unable to publish its descriptor.)
533    #[display("Onion Service not found")]
534    OnionServiceNotFound,
535
536    /// The target hidden service (`.onion` service) seems to be down
537    ///
538    /// We successfully obtained a hidden service descriptor for the service,
539    /// so we know it is supposed to exist,
540    /// but we weren't able to communicate with it via any of its
541    /// introduction points.
542    ///
543    /// This probably means that the hidden service is not running.
544    /// (It might mean that the introduction point relays are faulty.)
545    #[display("Onion Service not running")]
546    OnionServiceNotRunning,
547
548    /// Protocol trouble involving the target hidden service (`.onion` service)
549    ///
550    /// Something unexpected happened when trying to connect to the selected hidden service.
551    /// It seems to have been due to the hidden service violating the Tor protocols somehow.
552    #[display("Onion Service protocol failed (apparently due to service behaviour)")]
553    OnionServiceProtocolViolation,
554
555    /// The target hidden service (`.onion` service) is running but we couldn't connect to it,
556    /// and we aren't sure whose fault that is
557    ///
558    /// This might be due to malfunction on the part of the service,
559    /// or a relay being used as an introduction point or relay,
560    /// or failure of the underlying Tor network.
561    #[display("Onion Service not reachable (due to service, or Tor network, behaviour)")]
562    OnionServiceConnectionFailed,
563
564    /// We tried to connect to an onion service without authentication,
565    /// but it apparently requires authentication.
566    #[display("Onion service required authentication, but none was provided.")]
567    OnionServiceMissingClientAuth,
568
569    /// We tried to connect to an onion service that requires authentication, and
570    /// ours is wrong.
571    ///
572    /// This likely means that we need to use a different key for talking to
573    /// this onion service, or that it has revoked our permissions to reach it.
574    #[display("Onion service required authentication, but provided authentication was incorrect.")]
575    OnionServiceWrongClientAuth,
576
577    /// We tried to parse a `.onion` address, and found that it was not valid.
578    ///
579    /// This likely means that it was corrupted somewhere along its way from its
580    /// origin to our API surface.  It may be the wrong length, have invalid
581    /// characters, have an invalid version number, or have an invalid checksum.
582    #[display(".onion address was invalid.")]
583    OnionServiceAddressInvalid,
584
585    /// An resolve operation finished with an error.
586    ///
587    /// Contrary to [`RemoteHostNotFound`](ErrorKind::RemoteHostNotFound),
588    /// this can't mean "this is not a hostname".
589    /// This error should be retried.
590    #[display("remote hostname lookup failure")]
591    RemoteHostResolutionFailed,
592
593    /// Trouble involving a protocol we're using with a peer on the far side of the Tor network
594    ///
595    /// We were using a higher-layer protocol over a Tor connection,
596    /// and something went wrong.
597    /// This might be an error reported by the remote host within that higher protocol,
598    /// or a problem detected locally but relating to that higher protocol.
599    ///
600    /// The nature of the problem can vary:
601    /// examples could include:
602    /// failure to agree suitable parameters (incompatibility);
603    /// authentication problems (eg, TLS certificate trouble);
604    /// protocol violation by the peer;
605    /// peer refusing to provide service;
606    /// etc.
607    #[display("remote protocol violation")]
608    RemoteProtocolViolation,
609
610    /// An operation failed, and the relay in question reported that it's too
611    /// busy to answer our request.
612    #[display("relay too busy")]
613    RelayTooBusy,
614
615    /// We were asked to make an anonymous connection to a malformed address.
616    ///
617    /// This is probably because of a bad input from a user.
618    #[display("target address was invalid")]
619    InvalidStreamTarget,
620
621    /// We were asked to make an anonymous connection to a _locally_ disabled
622    /// address.
623    ///
624    /// For example, this kind of error can happen when try to connect to (e.g.)
625    /// `127.0.0.1` using a client that isn't configured with allow_local_addrs.
626    ///
627    /// Usually this means that you intended to reject the request as
628    /// nonsensical; but if you didn't, it probably means you should change your
629    /// configuration to allow what you want.
630    #[display("target address disabled locally")]
631    ForbiddenStreamTarget,
632
633    /// An operation failed in a transient way.
634    ///
635    /// This kind of error indicates that some kind of operation failed in a way
636    /// where retrying it again could likely have made it work.
637    ///
638    /// You should not generally see this kind of error returned directly to you
639    /// for high-level functions.  It should only be returned from lower-level
640    /// crates that do not automatically retry these failures.
641    // Errors with this kind should generally not return a `HasRetryTime::retry_time()` of `Never`.
642    #[display("un-retried transient failure")]
643    TransientFailure,
644
645    /// Bug, for example calling a function with an invalid argument.
646    ///
647    /// This kind of error is usually a programming mistake on the caller's part.
648    /// This is usually a bug in code calling Arti, but it might be a bug in Arti itself.
649    //
650    // Usually, use `bad_api_usage!` and `into_bad_api_usage!` and thereby `InternalError`,
651    // rather than inventing a new type with this kind.
652    //
653    // Errors with this kind should generally include a stack trace.  They are
654    // very like InternalError, in that they represent a bug in the program.
655    // The difference is that an InternalError, with kind `Internal`, represents
656    // a bug in arti, whereas errors with kind BadArgument represent bugs which
657    // could be (often, are likely to be) outside arti.
658    #[display("bad API usage (bug)")]
659    BadApiUsage,
660
661    /// We asked a relay to create or extend a circuit, and it declined.
662    ///
663    /// Either it gave an error message indicating that it refused to perform
664    /// the request, or the protocol gives it no room to explain what happened.
665    ///
666    /// This error is returned by higher-level functions only if it is the most informative
667    /// error after appropriate retries etc.
668    #[display("remote host refused our request")]
669    CircuitRefused,
670
671    /// We were unable to construct a path through the Tor network.
672    ///
673    /// Usually this indicates that there are too many user-supplied
674    /// restrictions for us to comply with.
675    ///
676    /// On test networks, it likely indicates that there aren't enough relays,
677    /// or that there aren't enough relays in distinct families.
678    //
679    // TODO: in the future, errors of this type should distinguish between
680    // cases where this happens because of a user restriction and cases where it
681    // happens because of a severely broken directory.
682    //
683    // The latter should be classified as TorDirectoryBroken.
684    #[display("could not construct a path")]
685    NoPath,
686
687    /// We were unable to find an exit relay with a certain set of desired
688    /// properties.
689    ///
690    /// Usually this indicates that there were too many user-supplied
691    /// restrictions on the exit for us to comply with, or that there was no
692    /// exit on the network supporting all of the ports that the user asked for.
693    //
694    // TODO: same as for NoPath.
695    #[display("no exit available for path")]
696    NoExit,
697
698    /// The Tor consensus directory is broken or unsuitable
699    ///
700    /// This could occur when running very old software
701    /// against the current Tor network,
702    /// so that the newer network is incompatible.
703    ///
704    /// It might also mean a catastrophic failure of the Tor network,
705    /// or that a deficient test network is in use.
706    ///
707    /// Currently some instances of this kind of problem
708    /// are reported as `NoPath` or `NoExit`.
709    #[display("Tor network consensus directory is not usable")]
710    TorDirectoryUnusable,
711
712    /// An operation failed because of _possible_ clock skew.
713    ///
714    /// The broken clock may be ours, or it may belong to another party on the
715    /// network. It's also possible that somebody else is lying about the time,
716    /// caching documents for far too long, or something like that.
717    #[display("possible clock skew detected")]
718    ClockSkew,
719
720    /// Internal error (bug) in Arti.
721    ///
722    /// A supposedly impossible problem has arisen.  This indicates a bug in
723    /// Arti; if the Arti version is relatively recent, please report the bug on
724    /// our [bug tracker](https://gitlab.torproject.org/tpo/core/arti/-/issues).
725    #[display("internal error (bug)")]
726    Internal,
727
728    /// Unclassified error
729    ///
730    /// Some other error occurred, which does not fit into any of the other kinds.
731    ///
732    /// This kind is provided for use by external code
733    /// hooking into or replacing parts of Arti.
734    /// It is never returned by the code in Arti (`arti-*` and `tor-*` crates).
735    #[display("unclassified error")]
736    Other,
737}
738
739/// Errors that can be categorized as belonging to an [`ErrorKind`]
740///
741/// The most important implementation of this trait is
742/// `arti_client::TorError`; however, other internal errors throughout Arti
743/// also implement it.
744pub trait HasKind {
745    /// Return the kind of this error.
746    fn kind(&self) -> ErrorKind;
747}
748
749#[cfg(feature = "futures")]
750impl HasKind for futures::task::SpawnError {
751    fn kind(&self) -> ErrorKind {
752        use ErrorKind as EK;
753        if self.is_shutdown() {
754            EK::ReactorShuttingDown
755        } else {
756            EK::Internal
757        }
758    }
759}
760
761impl HasKind for void::Void {
762    fn kind(&self) -> ErrorKind {
763        void::unreachable(*self)
764    }
765}
766
767impl HasKind for std::convert::Infallible {
768    fn kind(&self) -> ErrorKind {
769        unreachable!()
770    }
771}
772
773/// Sealed
774mod sealed {
775    /// Sealed
776    pub trait Sealed {}
777}