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}