rust_supervisor/dashboard/error.rs
1//! Structured dashboard IPC errors.
2//!
3//! The dashboard feature exchanges errors with relay code over JSON. This
4//! module keeps those errors typed so tests can assert code, stage, target, and
5//! retry behavior without parsing strings.
6
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10
11/// Error returned by target-side dashboard IPC handlers.
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Error)]
13#[error("{code} at {stage}: {message}")]
14pub struct DashboardError {
15 /// Stable machine-readable error code.
16 pub code: String,
17 /// Processing stage that produced the error.
18 pub stage: String,
19 /// Optional target process identifier related to the error.
20 pub target_id: Option<String>,
21 /// Human-readable diagnostic message.
22 pub message: String,
23 /// Whether a caller can retry after the reported condition changes.
24 pub retryable: bool,
25}
26
27impl DashboardError {
28 /// Creates a structured dashboard error.
29 ///
30 /// # Arguments
31 ///
32 /// - `code`: Stable machine-readable error code.
33 /// - `stage`: Processing stage that produced the error.
34 /// - `target_id`: Optional target process identifier.
35 /// - `message`: Human-readable diagnostic message.
36 /// - `retryable`: Whether a retry can later succeed.
37 ///
38 /// # Returns
39 ///
40 /// Returns a [`DashboardError`] value ready for JSON serialization.
41 pub fn new(
42 code: impl Into<String>,
43 stage: impl Into<String>,
44 target_id: Option<String>,
45 message: impl Into<String>,
46 retryable: bool,
47 ) -> Self {
48 Self {
49 code: code.into(),
50 stage: stage.into(),
51 target_id,
52 message: message.into(),
53 retryable,
54 }
55 }
56
57 /// Creates an unsupported method error.
58 ///
59 /// # Arguments
60 ///
61 /// - `method`: Method name rejected by the parser.
62 ///
63 /// # Returns
64 ///
65 /// Returns a non-retryable [`DashboardError`].
66 pub fn unsupported_method(method: impl AsRef<str>) -> Self {
67 Self::new(
68 "unsupported_method",
69 "protocol_parse",
70 None,
71 format!("unsupported dashboard IPC method {}", method.as_ref()),
72 false,
73 )
74 }
75
76 /// Creates a validation error.
77 ///
78 /// # Arguments
79 ///
80 /// - `stage`: Validation stage.
81 /// - `target_id`: Optional target process identifier.
82 /// - `message`: Human-readable validation message.
83 ///
84 /// # Returns
85 ///
86 /// Returns a non-retryable [`DashboardError`].
87 pub fn validation(
88 stage: impl Into<String>,
89 target_id: Option<String>,
90 message: impl Into<String>,
91 ) -> Self {
92 Self::new("validation_failed", stage, target_id, message, false)
93 }
94
95 /// Creates a target unavailable error.
96 ///
97 /// # Arguments
98 ///
99 /// - `stage`: Processing stage that tried to use the target.
100 /// - `target_id`: Target process identifier.
101 /// - `message`: Human-readable diagnostic message.
102 ///
103 /// # Returns
104 ///
105 /// Returns a retryable [`DashboardError`].
106 pub fn target_unavailable(
107 stage: impl Into<String>,
108 target_id: impl Into<String>,
109 message: impl Into<String>,
110 ) -> Self {
111 Self::new(
112 "target_unavailable",
113 stage,
114 Some(target_id.into()),
115 message,
116 true,
117 )
118 }
119}