Skip to main content

solti_discover/
errors.rs

1//! # Discovery error types.
2
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum DiscoverError {
7    #[error("invalid config: {0}")]
8    InvalidConfig(String),
9
10    #[error("failed to build task spec: {0}")]
11    SpecBuild(String),
12
13    #[cfg(feature = "grpc")]
14    #[error("failed to connect to control plane: {0}")]
15    GrpcTransport(#[from] tonic::transport::Error),
16
17    #[cfg(feature = "grpc")]
18    #[error("grpc call failed: {0}")]
19    GrpcStatus(#[source] Box<tonic::Status>),
20
21    #[cfg(feature = "http")]
22    #[error("http request failed: {0}")]
23    HttpRequest(#[from] reqwest::Error),
24
25    #[cfg(feature = "http")]
26    #[error("http status {code}: {body}")]
27    HttpStatus { code: u16, body: String },
28
29    #[cfg(feature = "http")]
30    #[error("invalid response: {0}")]
31    InvalidResponse(String),
32
33    #[error("control plane rejected sync: {reason}")]
34    Rejected {
35        reason: String,
36        retry_after_s: Option<i32>,
37    },
38
39    #[error("authentication failed: {reason}")]
40    AuthFailed { reason: String },
41}
42
43impl DiscoverError {
44    /// `true` for errors that indicate a misconfiguration, not a transient failure.
45    /// Sync treats these as terminal (Fatal) - the operator must act before the agent can make progress.
46    pub fn is_terminal(&self) -> bool {
47        matches!(
48            self,
49            DiscoverError::AuthFailed { .. } | DiscoverError::InvalidConfig(_)
50        )
51    }
52}
53
54#[cfg(feature = "grpc")]
55impl From<tonic::Status> for DiscoverError {
56    fn from(status: tonic::Status) -> Self {
57        DiscoverError::GrpcStatus(Box::new(status))
58    }
59}