Skip to main content

kimi_wire/
error.rs

1use std::time::Duration;
2
3/// Errors that can occur when interacting with the Kimi Wire protocol.
4///
5/// ADR: `std::io::Error` and `serde_json::Error` are flattened to `String`
6/// variants (`Io(String)`, `JsonParse(String)`) rather than preserved with
7/// `#[source]`. This is a deliberate trade-off: `WireError` implements
8/// `Clone + PartialEq`, which is required for test ergonomics (comparing
9/// expected vs actual errors, injecting errors into mock clients). Dynamic
10/// error types (`Box<dyn std::error::Error>`) are neither `Clone` nor
11/// `PartialEq`, and `#[source]` would make the enum non-cloneable. Callers
12/// still receive the full error message; the cause chain is simply collapsed
13/// into the display string at the boundary.
14#[derive(thiserror::Error, Debug, Clone, PartialEq)]
15#[non_exhaustive]
16pub enum WireError {
17    /// The wire stream closed unexpectedly.
18    #[error("wire stream closed")]
19    StreamClosed,
20
21    /// A read or write operation timed out.
22    #[error("wire I/O timed out after {0:?}")]
23    Timeout(Duration),
24
25    /// Failed to spawn the Kimi CLI process.
26    #[error("failed to spawn process: {0}")]
27    SpawnFailed(String),
28
29    /// Failed to parse a JSON message.
30    #[error("json parse error: {0}")]
31    JsonParse(String),
32
33    /// Failed to serialize a value to JSON.
34    #[error("json serialization error: {0}")]
35    JsonSerialize(String),
36
37    /// The server returned a JSON-RPC error response.
38    #[error("wire request failed: {message} (code: {code})")]
39    RequestFailed {
40        /// JSON-RPC error code.
41        code: i32,
42        /// Error message from the server.
43        message: String,
44    },
45
46    /// Received a response with an unexpected request id.
47    #[error("unexpected response id: expected {expected}, got {got}")]
48    UnexpectedResponseId {
49        /// Expected request id.
50        expected: String,
51        /// Actual request id received.
52        got: String,
53    },
54
55    /// The server does not support the requested method.
56    #[error("method not found: {0}")]
57    MethodNotFound(String),
58
59    /// An unknown wire message type was received.
60    #[error("unknown wire message type: {0}")]
61    UnknownMessageType(String),
62
63    /// The payload was not a JSON object.
64    #[error("wire message payload must be a json object")]
65    InvalidPayloadType,
66
67    /// An I/O error occurred.
68    #[error("I/O error: {0}")]
69    Io(String),
70
71    /// A generic internal error.
72    #[error("internal error: {0}")]
73    Internal(String),
74}
75
76impl From<std::io::Error> for WireError {
77    fn from(err: std::io::Error) -> Self {
78        Self::Io(err.to_string())
79    }
80}
81
82impl From<serde_json::Error> for WireError {
83    fn from(err: serde_json::Error) -> Self {
84        if err.is_io() {
85            Self::Io(err.to_string())
86        } else {
87            Self::JsonParse(err.to_string())
88        }
89    }
90}