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

Loading…

RPC Service Errors

Relevant source files

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:

VariantDescriptionExample Use Cases
Rpc(RpcServiceErrorPayload)An error originating from the remote service method executionMethod not found, business logic failure, panics in handler
Transport(io::Error)An error in the underlying transport or protocol layerConnection dropped, timeout, frame decode failure

Sources:

RpcServiceErrorPayload Structure

When an RPC method fails on the server side, the error details are transmitted using RpcServiceErrorPayload:

FieldTypeDescription
codeRpcServiceErrorCodeCategorizes the error (NotFound, Fail, System)
messageStringHuman-readable error message from the service handler

Sources:

RpcServiceErrorCode Enum

The RpcServiceErrorCode categorizes RPC errors into three types:

CodeMeaningWhen Used
NotFoundThe requested method ID does not exist on the serverMethod dispatch fails due to unregistered handler
FailThe method executed but returned a business logic errorHandler returns Err in its result type
SystemA system-level error occurred during method executionPanics, internal errors, resource exhaustion

Sources:


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

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 ValueDescriptionMaps to RpcServiceErrorCode
SuccessMethod executed successfullyN/A (no error)
MethodNotFoundHandler not registered for method IDNotFound
FailHandler returned errorFail
SystemErrorHandler panicked or system errorSystem

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

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:


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:


Test Examples

Handling MethodNotFound Error

Test demonstrating a method not found scenario:

Pattern:

  1. Mock sender emits Err(RpcServiceError::Rpc) with code: NotFound
  2. Caller receives the error through the buffered call
  3. Error code and message are preserved

Sources:

Handling System Error

Test demonstrating a system-level error (e.g., panic in handler):

Pattern:

  1. Mock sender emits Err(RpcServiceError::Rpc) with code: System
  2. Error message includes panic details
  3. 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:


Summary Table

Error OriginStatus/VariantRpcServiceErrorCodeDescription
Handler not registeredMethodNotFoundNotFoundThe requested method ID has no registered handler on the server
Handler returns ErrFailFailThe handler executed but returned a business logic error
Handler panicsSystemErrorSystemThe handler panicked or encountered an internal system error
Connection droppedN/AN/AWrapped in RpcServiceError::Transport(io::Error)
Frame decode failureN/AN/AWrapped in RpcServiceError::Transport(io::Error)
Disconnected call attemptN/AN/Aio::ErrorKind::ConnectionAborted in Transport variant

Sources: