Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

GitHub

This documentation is part of the "Projects with Books" initiative at zenOSmosis.

The source code for this project is available on GitHub.

RPC Service Errors

Relevant source files

Purpose and Scope

This document describes the error handling system used by the RPC framework layer in rust-muxio. It covers the RpcServiceError type, its variants, error codes, and how errors propagate between client and server. For information about lower-level transport errors and connection failures, see Transport Errors. For details on how errors are created in service handlers, see Service Endpoint Interface.


Error Type Hierarchy

The RPC framework uses a structured error system centered around the RpcServiceError enum, which distinguishes between protocol-level RPC errors and underlying transport errors.

Sources:

graph TB
    RSE["RpcServiceError"]
RSE --> Rpc["Rpc(RpcServiceErrorPayload)"]
RSE --> Transport["Transport(io::Error)"]
Rpc --> Payload["RpcServiceErrorPayload"]
Payload --> Code["code: RpcServiceErrorCode"]
Payload --> Message["message: String"]
Code --> NotFound["NotFound"]
Code --> Fail["Fail"]
Code --> System["System"]
NotFound -.- NF_Desc["Method not registered\non server"]
Fail -.- Fail_Desc["Application-level\nerror from handler"]
System -.- Sys_Desc["Server panic or\ninternal error"]

RpcServiceError Variants

The RpcServiceError type has two primary variants that separate RPC protocol errors from transport layer failures.

Rpc Variant

The Rpc variant wraps an RpcServiceErrorPayload and represents errors that occur at the RPC protocol layer. These errors are serialized and transmitted from the server to the client as part of the RPC protocol itself.

Structure:

  • code : An RpcServiceErrorCode enum indicating the error category
  • message : A human-readable error description string

Example usage from tests:

Sources:

Transport Variant

The Transport variant wraps a standard io::Error and represents errors that occur in the underlying transport layer, such as serialization failures or network issues that prevent the RPC from completing.

Example usage:

Sources:


RpcServiceErrorCode Values

The RpcServiceErrorCode enum defines standardized error categories used throughout the RPC system. Each code has specific semantics for how the error should be interpreted and potentially recovered from.

Error CodeMeaningTypical Scenario
NotFoundThe requested method ID is not registered on the serverClient calls a method that the server doesn't implement
FailApplication-level error returned by the handlerBusiness logic failure (e.g., "user not found", "invalid input")
SystemInternal server error or panic in the handlerHandler panicked, internal consistency error, or unexpected condition

NotFound Error Code

Used when a client attempts to invoke an RPC method that the server has not registered. This typically indicates a version mismatch between client and server service definitions.

Test example:

Sources:

Fail Error Code

Used for application-level errors that are part of normal business logic. These errors are expected and recoverable.

Test example:

Sources:

System Error Code

Used for internal server errors, including handler panics or unexpected system failures. These typically indicate bugs or serious issues on the server side.

Test example:

Sources:


sequenceDiagram
    participant Client as "RpcCallPrebuffered\n::call()"
    participant CallerIface as "RpcServiceCaller\nInterface"
    participant Dispatcher as "RpcDispatcher"
    participant Transport as "WebSocket"
    participant ServerDisp as "Server\nRpcDispatcher"
    participant Endpoint as "RpcServiceEndpoint\nInterface"
    participant Handler as "Method Handler"
    
    Client->>CallerIface: call_rpc_buffered(request)
    CallerIface->>Dispatcher: Register request
    Dispatcher->>Transport: Send RPC frames
    
    Transport->>ServerDisp: Receive frames
    ServerDisp->>Endpoint: dispatch by METHOD_ID
    Endpoint->>Handler: invoke handler
    
    Note over Handler: Handler returns\nErr("Addition failed")
    
    Handler-->>Endpoint: Err(String)
    
    Note over Endpoint: Convert to RpcServiceError::Rpc\nwith code=System
    
    Endpoint-->>ServerDisp: Serialize error payload
    ServerDisp-->>Transport: Send error response frames
    
    Transport-->>Dispatcher: Receive error frames
    Dispatcher-->>CallerIface: Deserialize error
    CallerIface-->>Client: Err(RpcServiceError::Rpc)
    
    Note over Client: Pattern match on error:\ncode and message available

Error Propagation Flow

This sequence diagram illustrates how errors propagate from a server-side handler back to the client, including serialization and protocol-level wrapping.

Sources:


Error Creation on Server Side

Server-side handlers can return errors in multiple ways, all of which are converted to RpcServiceError by the endpoint interface.

Handler Return Types

Handlers registered via register_prebuffered return Result<Vec<u8>, E> where E implements Into<RpcServiceError>. The most common patterns are:

Returning a String error:

This automatically converts to RpcServiceError::Rpc with code: RpcServiceErrorCode::System.

Sources:

graph LR
 
   Request["RpcRequest\nmethod_id=12345"] --> Lookup["Endpoint method\nlookup"]
Lookup -->|Not found| AutoError["Auto-generate\nRpcServiceError::Rpc"]
AutoError --> ErrorPayload["RpcServiceErrorPayload\ncode=NotFound"]
ErrorPayload --> Response["Send error response\nto client"]

Method Not Found Errors

When a client calls a method that isn't registered, the server's endpoint interface automatically generates a NotFound error without involving any handler:

Sources:


Error Handling on Client Side

Clients receive errors as part of the normal RPC response flow and must pattern match on the error type to handle different scenarios appropriately.

Pattern Matching on Error Codes

The recommended pattern for handling RPC errors is to match on the RpcServiceError variants and then examine the error code:

Sources:

Error Propagation Through RpcCallPrebuffered

The RpcCallPrebuffered trait implementation automatically propagates errors from the underlying call_rpc_buffered method. It handles two levels of Result nesting:

  1. Outer Result : Represents transport-level success/failure
  2. Inner Result : Contains either decoded response or RpcServiceError::Rpc

Sources:


Common Error Scenarios

Scenario 1: Unregistered Method Call

Situation: Client calls a method that the server doesn't have registered.

Error Flow:

  1. Client encodes request and sends to server
  2. Server dispatcher receives frames and extracts METHOD_ID
  3. Endpoint lookup fails to find handler
  4. Server automatically creates RpcServiceError::Rpc with code: NotFound
  5. Error is serialized and sent back to client
  6. Client receives and deserializes the error

Client-side result:

Sources:

Scenario 2: Handler Returns Application Error

Situation: Handler logic determines that the request cannot be fulfilled due to business logic constraints.

Error Flow:

  1. Server invokes handler with decoded request
  2. Handler returns Err("validation failed")
  3. Endpoint converts string to RpcServiceError::Rpc with code: System
  4. Error is serialized and transmitted
  5. Client receives error with code and message

Client-side result:

Sources:

Scenario 3: Deserialization Failure

Situation: Client successfully receives response bytes but fails to deserialize them into the expected type.

Error Flow:

  1. Server sends valid response bytes
  2. Client dispatcher reassembles payload
  3. decode_response closure returns io::Error
  4. Error is wrapped as RpcServiceError::Transport

Client-side result:

Sources:


Integration with Transport Layer

While this document focuses on RPC-level errors, it's important to understand how these errors interact with transport-level failures:

LayerError TypeScope
RPC ProtocolRpcServiceError::RpcMethod not found, handler failures, application errors
TransportRpcServiceError::TransportSerialization, deserialization, io::Error
ConnectionConnection state changesDisconnection, reconnection (see Transport State Management)

The separation ensures that RPC-level errors (which are part of the protocol) remain distinct from transport-level errors (which indicate infrastructure failures).

Sources:

Dismiss

Refresh this wiki

Enter email to refresh