Documentation index

Error Handling

The Slipstream SDK uses a unified error type across all three languages.

SdkError Variants

VariantDescriptionRetryable
ConfigInvalid configurationNo
ConnectionNetwork/connection errorYes
AuthInvalid or expired API keyNo
ProtocolProtocol-level errorYes
TransactionTransaction processing errorNo
TimeoutRequest timed outYes
AllProtocolsFailedAll protocols in fallback chain failedYes
RateLimitedToo many requestsYes
NotConnectedClient not connectedYes
StreamClosedStream subscription closedYes
InsufficientTokensNot enough tokensNo
InternalInternal server errorYes

Error Handling — Rust

Rust
use allenhark_slipstream::SdkError;

match client.submit_transaction(&tx_bytes).await {
    Ok(result) => println!("Success: {:?}", result.signature),
    Err(SdkError::Auth(msg)) => {
        eprintln!("Authentication error: {} — check your API key", msg);
    }
    Err(SdkError::InsufficientTokens) => {
        eprintln!("Not enough tokens — deposit SOL to continue");
        let deposit = client.get_deposit_address().await?;
        eprintln!("Deposit to: {:?}", deposit);
    }
    Err(SdkError::RateLimited(msg)) => {
        eprintln!("Rate limited: {}", msg);
        // SDK retries automatically based on config
    }
    Err(SdkError::Timeout(duration)) => {
        eprintln!("Timed out after {:?}", duration);
    }
    Err(SdkError::AllProtocolsFailed) => {
        eprintln!("All protocols failed — check network connectivity");
    }
    Err(SdkError::Connection(msg)) => {
        eprintln!("Connection error: {}", msg);
        // SDK will auto-reconnect on next call
    }
    Err(SdkError::NotConnected) => {
        eprintln!("Not connected — reconnecting...");
    }
    Err(SdkError::StreamClosed) => {
        eprintln!("Stream closed — resubscribe");
    }
    Err(e) => eprintln!("Unexpected error: {}", e),
}

Error Handling — TypeScript

TypeScript
import { SlipstreamClient } from "@allenhark/slipstream";

try {
    const result = await client.submitTransaction(txBytes);
    console.log("Success:", result.signature);
} catch (err: any) {
    switch (err.code) {
        case "AUTH":
            console.error("Auth error — check your API key");
            break;
        case "INSUFFICIENT_TOKENS":
            console.error("Not enough tokens");
            const deposit = await client.getDepositAddress();
            console.error("Deposit to:", deposit);
            break;
        case "RATE_LIMITED":
            console.error("Rate limited:", err.message);
            break;
        case "TIMEOUT":
            console.error("Request timed out");
            break;
        case "ALL_PROTOCOLS_FAILED":
            console.error("All protocols failed");
            break;
        case "CONNECTION":
            console.error("Connection error:", err.message);
            break;
        case "NOT_CONNECTED":
            console.error("Not connected");
            break;
        default:
            console.error("Unexpected error:", err);
    }
}

Error Handling — Python

Python
from allenhark_slipstream import SdkError

try:
    result = await client.submit_transaction(tx_bytes)
    print(f"Success: {result.signature}")
except SdkError as e:
    if e.is_auth():
        print(f"Auth error — check your API key: {e}")
    elif e.is_insufficient_tokens():
        print("Not enough tokens — deposit SOL")
    elif e.is_rate_limited():
        print(f"Rate limited: {e}")
    elif e.is_timeout():
        print("Request timed out")
    elif e.is_connection():
        print(f"Connection error: {e}")
    else:
        print(f"Error: {e}")

Retry Configuration

The SDK has built-in retry logic with configurable backoff.

Config-Level Retries — Rust

Rust
let config = Config::builder()
    .api_key("sk_live_...")
    .max_retries(3)
    .retry_backoff(BackoffStrategy::Exponential)
    .build()?;

Per-Request Retries — Rust

Rust
let result = client.submit_transaction_with_options(&tx_bytes, &SubmitOptions {
    max_retries: 5,
    retry: Some(RetryOptions {
        max_retries: 5,
        backoff_base_ms: 100,
        cross_sender_retry: true, // Try a different sender on retry
    }),
    ..Default::default()
}).await?;

Backoff Strategies

StrategyDescription
LinearWait = base_ms * attempt
ExponentialWait = base_ms * 2^attempt (default)

Connection Events

Monitor connection state changes.

Events — Rust

Rust
println!("Connected: {}", client.is_connected());

let info = client.connection_info();
println!("Session: {}, Protocol: {:?}", info.session_id, info.protocol);

Events — TypeScript

TypeScript
client.on("connected", () => console.log("Connected!"));
client.on("disconnected", () => console.log("Disconnected"));
client.on("error", (err) => console.error("Error:", err));

console.log("Connected:", client.isConnected());

Events — Python

Python
@client.on("connected")
async def on_connected():
    print("Connected!")

@client.on("disconnected")
async def on_disconnected():
    print("Disconnected")

@client.on("error")
async def on_error(err):
    print(f"Error: {err}")

Performance Metrics

Track success rates and latency.

Metrics — Rust

Rust
let metrics = client.metrics();
println!("Submitted: {}", metrics.transactions_submitted);
println!("Confirmed: {}", metrics.transactions_confirmed);
println!("Avg latency: {:.1}ms", metrics.average_latency_ms);
println!("Success rate: {:.1}%", metrics.success_rate * 100.0);

Metrics — TypeScript

TypeScript
const metrics = client.metrics();
console.log(`Success rate: ${(metrics.successRate * 100).toFixed(1)}%`);
console.log(`Avg latency: ${metrics.averageLatencyMs.toFixed(1)}ms`);

Next Steps