@@ -18,17 +18,32 @@ pub(super) fn build_request(method: &str, params: &Value) -> String {
1818 . to_string ( )
1919}
2020
21+ /// Extract structured error from a JSON-RPC 2.0 response.
22+ ///
23+ /// Returns `Some((code, message))` if the response contains an `error` field,
24+ /// `None` if no error is present. Handles both standard JSON-RPC error objects
25+ /// (`{"code": -32600, "message": "..."}`) and bare string errors.
26+ ///
27+ /// Pattern source: wetSpring V123 / healthSpring V30 centralized RPC error extraction.
28+ pub ( super ) fn extract_rpc_error ( v : & Value ) -> Option < ( i64 , String ) > {
29+ let error = v. get ( "error" ) ?;
30+ let code = error. get ( "code" ) . and_then ( Value :: as_i64) . unwrap_or ( -32000 ) ;
31+ let message = error
32+ . get ( "message" )
33+ . and_then ( Value :: as_str)
34+ . map ( String :: from)
35+ . or_else ( || error. as_str ( ) . map ( String :: from) )
36+ . unwrap_or_else ( || "unknown RPC error" . to_string ( ) ) ;
37+ Some ( ( code, message) )
38+ }
39+
2140/// Parse a JSON-RPC 2.0 response, extracting the result or error.
2241pub ( super ) fn parse_rpc_response ( response : & str ) -> Result < String > {
2342 let v: Value = serde_json:: from_str ( response)
2443 . map_err ( |e| BiomeOsError :: Protocol ( format ! ( "invalid JSON-RPC response: {e}" ) ) ) ?;
2544
26- if let Some ( error) = v. get ( "error" ) {
27- let msg = error
28- . get ( "message" )
29- . and_then ( Value :: as_str)
30- . unwrap_or ( "unknown RPC error" ) ;
31- return Err ( BiomeOsError :: Protocol ( msg. to_string ( ) ) ) ;
45+ if let Some ( ( _code, message) ) = extract_rpc_error ( & v) {
46+ return Err ( BiomeOsError :: Protocol ( message) ) ;
3247 }
3348
3449 match v. get ( "result" ) {
@@ -45,12 +60,8 @@ pub(super) fn response_has_error(response: &str) -> Result<()> {
4560 let v: Value = serde_json:: from_str ( response)
4661 . map_err ( |e| BiomeOsError :: Protocol ( format ! ( "invalid JSON-RPC response: {e}" ) ) ) ?;
4762
48- if let Some ( error) = v. get ( "error" ) {
49- let msg = error
50- . get ( "message" )
51- . and_then ( Value :: as_str)
52- . unwrap_or ( "unknown RPC error" ) ;
53- return Err ( BiomeOsError :: Protocol ( msg. to_string ( ) ) ) ;
63+ if let Some ( ( _code, message) ) = extract_rpc_error ( & v) {
64+ return Err ( BiomeOsError :: Protocol ( message) ) ;
5465 }
5566
5667 Ok ( ( ) )
@@ -120,4 +131,37 @@ mod tests {
120131 let resp = r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"bad"},"id":1}"# ;
121132 assert ! ( response_has_error( resp) . is_err( ) ) ;
122133 }
134+
135+ #[ test]
136+ fn extract_rpc_error_standard ( ) {
137+ let v: Value =
138+ serde_json:: from_str ( r#"{"error":{"code":-32601,"message":"method not found"}}"# )
139+ . unwrap ( ) ;
140+ let ( code, msg) = extract_rpc_error ( & v) . unwrap ( ) ;
141+ assert_eq ! ( code, -32601 ) ;
142+ assert_eq ! ( msg, "method not found" ) ;
143+ }
144+
145+ #[ test]
146+ fn extract_rpc_error_bare_string ( ) {
147+ let v: Value = serde_json:: from_str ( r#"{"error":"something went wrong"}"# ) . unwrap ( ) ;
148+ let ( code, msg) = extract_rpc_error ( & v) . unwrap ( ) ;
149+ assert_eq ! ( code, -32000 ) ;
150+ assert_eq ! ( msg, "something went wrong" ) ;
151+ }
152+
153+ #[ test]
154+ fn extract_rpc_error_none_when_no_error ( ) {
155+ let v: Value = serde_json:: from_str ( r#"{"result":"ok"}"# ) . unwrap ( ) ;
156+ assert ! ( extract_rpc_error( & v) . is_none( ) ) ;
157+ }
158+
159+ #[ test]
160+ fn extract_rpc_error_is_method_not_found ( ) {
161+ let v: Value =
162+ serde_json:: from_str ( r#"{"error":{"code":-32601,"message":"method not found"}}"# )
163+ . unwrap ( ) ;
164+ let ( code, _) = extract_rpc_error ( & v) . unwrap ( ) ;
165+ assert_eq ! ( code, -32601 ) ;
166+ }
123167}
0 commit comments