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
Loading…
RPC Service Errors
Relevant source files
- extensions/muxio-rpc-service-caller/src/caller_interface.rs
- extensions/muxio-rpc-service-caller/tests/prebuffered_caller_tests.rs
Purpose and Scope
This page documents the RPC-level error types, error codes, and error propagation mechanisms in the muxio RPC framework. It covers how service method failures are represented, encoded in the binary protocol, and delivered to callers. For information about lower-level transport and framing errors (such as connection failures and frame decode errors), see Transport and Framing Errors.
Error Type Hierarchy
The muxio RPC framework defines a structured error system that distinguishes between RPC-level errors (method failures, not found errors) and transport-level errors (connection issues, protocol violations).
RpcServiceError Enum
The RpcServiceError is the primary error type returned by RPC calls. It has two variants:
| Variant | Description | Example Use Cases |
|---|---|---|
Rpc(RpcServiceErrorPayload) | An error originating from the remote service method execution | Method not found, business logic failure, panics in handler |
Transport(io::Error) | An error in the underlying transport or protocol layer | Connection dropped, timeout, frame decode failure |
Sources:
- extensions/muxio-rpc-service-caller/src/caller_interface.rs16
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:49-52
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:193-198
RpcServiceErrorPayload Structure
When an RPC method fails on the server side, the error details are transmitted using RpcServiceErrorPayload:
| Field | Type | Description |
|---|---|---|
code | RpcServiceErrorCode | Categorizes the error (NotFound, Fail, System) |
message | String | Human-readable error message from the service handler |
Sources:
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:194-197
- extensions/muxio-rpc-service-caller/tests/prebuffered_caller_tests.rs:155-158
RpcServiceErrorCode Enum
The RpcServiceErrorCode categorizes RPC errors into three types:
| Code | Meaning | When Used |
|---|---|---|
NotFound | The requested method ID does not exist on the server | Method dispatch fails due to unregistered handler |
Fail | The method executed but returned a business logic error | Handler returns Err in its result type |
System | A system-level error occurred during method execution | Panics, internal errors, resource exhaustion |
Sources:
- extensions/muxio-rpc-service-caller/src/caller_interface.rs196
- extensions/muxio-rpc-service-caller/src/caller_interface.rs208
- extensions/muxio-rpc-service-caller/src/caller_interface.rs226
- extensions/muxio-rpc-service-caller/tests/prebuffered_caller_tests.rs156
Error Propagation Flow
The following diagram illustrates how errors flow from the server-side handler through the protocol layers to the client:
Sources:
sequenceDiagram
participant Handler as "Service Handler"
participant Endpoint as "RpcServiceEndpoint"
participant ServerDisp as "Server RpcDispatcher"
participant Protocol as "Binary Protocol"
participant ClientDisp as "Client RpcDispatcher"
participant RecvFn as "recv_fn Callback"
participant Channel as "DynamicSender"
participant Caller as "RPC Caller"
Note over Handler,Caller: Error Case: Handler Fails
Handler->>Endpoint: Return Err(error)
Endpoint->>ServerDisp: respond() with RpcResultStatus
ServerDisp->>Protocol: Encode status in metadata_bytes
Protocol->>Protocol: Transmit error message as payload
Protocol->>ClientDisp: RpcStreamEvent::Header
ClientDisp->>RecvFn: Event with RpcResultStatus
RecvFn->>RecvFn: Extract status from metadata_bytes[0]
RecvFn->>RecvFn: Buffer error payload
Protocol->>ClientDisp: RpcStreamEvent::PayloadChunk
ClientDisp->>RecvFn: Error message bytes
RecvFn->>RecvFn: Accumulate in error_buffer
Protocol->>ClientDisp: RpcStreamEvent::End
ClientDisp->>RecvFn: Stream complete
RecvFn->>RecvFn: Convert RpcResultStatus to RpcServiceError
RecvFn->>Channel: Send Err(RpcServiceError::Rpc)
Channel->>Caller: Receive error from stream
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:119-134
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:136-173
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:175-244
Error Encoding in RPC Protocol
RpcResultStatus Enum
The RpcResultStatus is encoded in the first byte of the rpc_metadata_bytes field in the RpcHeader. This status indicates whether the RPC call succeeded or failed, and if it failed, what category of failure occurred.
| Status Value | Description | Maps to RpcServiceErrorCode |
|---|---|---|
Success | Method executed successfully | N/A (no error) |
MethodNotFound | Handler not registered for method ID | NotFound |
Fail | Handler returned error | Fail |
SystemError | Handler panicked or system error | System |
Sources:
Status Extraction and Error Construction
The recv_fn callback extracts the status from the response header and buffers any error payload:
Sources:
graph TB
Header["RpcStreamEvent::Header\nrpc_metadata_bytes[0]"]
Extract["Extract RpcResultStatus\nvia try_from(byte)"]
Store["Store status in\nStdMutex<Option<RpcResultStatus>>"]
PayloadChunk["RpcStreamEvent::PayloadChunk\nbytes"]
CheckStatus{"Status is\nSuccess?"}
SendSuccess["Send Ok(bytes)\nto DynamicSender"]
BufferError["Accumulate in\nerror_buffer"]
End["RpcStreamEvent::End"]
MatchStatus{"Match\nfinal status"}
CreateNotFound["RpcServiceError::Rpc\ncode: NotFound"]
CreateFail["RpcServiceError::Rpc\ncode: Fail"]
CreateSystem["RpcServiceError::Rpc\ncode: System\nmessage: from buffer"]
SendError["Send Err(error)\nto DynamicSender"]
Header --> Extract
Extract --> Store
PayloadChunk --> CheckStatus
CheckStatus -->|Yes| SendSuccess
CheckStatus -->|No| BufferError
End --> MatchStatus
MatchStatus -->|MethodNotFound| CreateNotFound
MatchStatus -->|Fail| CreateFail
MatchStatus -->|SystemError| CreateSystem
CreateNotFound --> SendError
CreateFail --> SendError
CreateSystem --> SendError
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:119-134
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:136-173
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:186-238
Error Handling in Caller Interface
The RpcServiceCallerInterface trait defines error handling at two levels: during call setup and during response processing.
Connection State Validation
Before initiating an RPC call, the caller checks the connection state:
Sources:
Response Stream Error Handling
The recv_fn callback processes three types of events that can result in errors:
graph TD
ErrorEvent["RpcStreamEvent::Error\nframe_decode_error"]
CreateTransportErr["Create RpcServiceError::Transport\nio::Error::ConnectionAborted\nmessage: frame_decode_error.to_string()"]
NotifyReady["Send Err to ready_rx\nif not yet signaled"]
SendToChannel["Send Err to DynamicSender\nif still available"]
DropSender["Drop DynamicSender\nclose channel"]
ErrorEvent --> CreateTransportErr
CreateTransportErr --> NotifyReady
NotifyReady --> SendToChannel
SendToChannel --> DropSender
Error Event from Transport
When a RpcStreamEvent::Error is received (indicating a frame decode error or transport failure):
Sources:
RPC-Level Error from End Event
When a RpcStreamEvent::End is received with a non-success status:
Sources:
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:175-244
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:186-238
graph TD
StartBuffered["call_rpc_buffered()"]
CallStreaming["call_rpc_streaming()\nDynamicChannelType::Unbounded"]
InitBuffers["success_buf = Vec::new()\nerr = None"]
LoopStart{"stream.next().await"}
MatchResult{"Match result"}
OkChunk["Ok(chunk)"]
ErrValue["Err(e)"]
ExtendBuf["success_buf.extend(chunk)"]
StoreErr["err = Some(e)\nbreak loop"]
CheckErr{"err.is_some()?"}
ReturnErr["Return Ok(encoder, Err(err))"]
Decode["decode(&success_buf)"]
ReturnOk["Return Ok(encoder, Ok(decoded))"]
StartBuffered --> CallStreaming
CallStreaming --> InitBuffers
InitBuffers --> LoopStart
LoopStart -->|Some result| MatchResult
LoopStart -->|None| CheckErr
MatchResult --> OkChunk
MatchResult --> ErrValue
OkChunk --> ExtendBuf
ExtendBuf --> LoopStart
ErrValue --> StoreErr
StoreErr --> CheckErr
CheckErr -->|Yes| ReturnErr
CheckErr -->|No| Decode
Decode --> ReturnOk
Buffered Call Error Aggregation
The call_rpc_buffered method consumes a streaming response and returns either the complete success payload or the first error encountered:
Sources:
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:351-399
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:373-398
Test Examples
Handling MethodNotFound Error
Test demonstrating a method not found scenario:
Pattern:
- Mock sender emits
Err(RpcServiceError::Rpc)withcode: NotFound - Caller receives the error through the buffered call
- Error code and message are preserved
Sources:
Handling System Error
Test demonstrating a system-level error (e.g., panic in handler):
Pattern:
- Mock sender emits
Err(RpcServiceError::Rpc)withcode: System - Error message includes panic details
- Prebuffered trait call propagates the error to caller
Sources:
Error Variant Matching
When handling RpcServiceError in application code, match on the variants:
match result {
Ok(value) => { /* handle success */ },
Err(RpcServiceError::Rpc(payload)) => {
match payload.code {
RpcServiceErrorCode::NotFound => { /* method not registered */ },
RpcServiceErrorCode::Fail => { /* business logic error */ },
RpcServiceErrorCode::System => { /* handler panic or internal error */ },
}
},
Err(RpcServiceError::Transport(io_err)) => { /* connection or protocol error */ },
}
Sources:
- extensions/muxio-rpc-service-caller/tests/prebuffered_caller_tests.rs:170-176
- extensions/muxio-rpc-service-caller/tests/prebuffered_caller_tests.rs:205-211
Summary Table
| Error Origin | Status/Variant | RpcServiceErrorCode | Description |
|---|---|---|---|
| Handler not registered | MethodNotFound | NotFound | The requested method ID has no registered handler on the server |
Handler returns Err | Fail | Fail | The handler executed but returned a business logic error |
| Handler panics | SystemError | System | The handler panicked or encountered an internal system error |
| Connection dropped | N/A | N/A | Wrapped in RpcServiceError::Transport(io::Error) |
| Frame decode failure | N/A | N/A | Wrapped in RpcServiceError::Transport(io::Error) |
| Disconnected call attempt | N/A | N/A | io::ErrorKind::ConnectionAborted in Transport variant |
Sources:
- extensions/muxio-rpc-service-caller/src/caller_interface.rs16
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:186-238
- extensions/muxio-rpc-service-caller/src/caller_interface.rs:246-284