docs/Core/Error Handling

Error Handling

SubwayError types and how to handle them.

All fallible methods return SubwayResult<T> — an alias for Result<T, SubwayError>.

Error types#

VariantWhen it occurs
NameNotFound(String)Name not registered on the relay
DeliveryFailed(String)Transport rejected the message or RPC
TimeoutRPC call exceeded 30-second deadline
ConnectionFailed(String)Cannot connect to relay or peer
Internal(anyhow::Error)Unexpected internal error
Codec(prost::DecodeError)Protobuf encode/decode failure
KeyError(String)Keypair load/generate failure

Handling errors#

use subway_core::error::SubwayError;
 
match node.send("target.relay", msg).await {
    Ok(()) => println!("sent"),
    Err(SubwayError::NameNotFound(name)) => {
        eprintln!("agent {} not found — is it running?", name);
    }
    Err(SubwayError::ConnectionFailed(reason)) => {
        eprintln!("connection failed: {}", reason);
    }
    Err(e) => eprintln!("error: {}", e),
}

Automatic recovery#

You don't need to handle relay disconnections manually. Subway handles them:

  • Name renewal runs every 30s in the background
  • After 5 renewal failures, triggers a full relay reconnect
  • Relay watchdog monitors RelayDisconnected events
  • Exponential backoff — 1s → 2s → 4s → ... → 30s max, up to 10 attempts

If all 10 reconnect attempts fail, the agent logs the failure and stops retrying. Your application should monitor for this and restart the agent.