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

1use allenhark_slipstream::SdkError;
2
3match client.submit_transaction(&tx_bytes).await {
4    Ok(result) => println!("Success: {:?}", result.signature),
5    Err(SdkError::Auth(msg)) => {
6        eprintln!("Authentication error: {} — check your API key", msg);
7    }
8    Err(SdkError::InsufficientTokens) => {
9        eprintln!("Not enough tokens — deposit SOL to continue");
10        let deposit = client.get_deposit_address().await?;
11        eprintln!("Deposit to: {:?}", deposit);
12    }
13    Err(SdkError::RateLimited(msg)) => {
14        eprintln!("Rate limited: {}", msg);
15        // SDK retries automatically based on config
16    }
17    Err(SdkError::Timeout(duration)) => {
18        eprintln!("Timed out after {:?}", duration);
19    }
20    Err(SdkError::AllProtocolsFailed) => {
21        eprintln!("All protocols failed — check network connectivity");
22    }
23    Err(SdkError::Connection(msg)) => {
24        eprintln!("Connection error: {}", msg);
25        // SDK will auto-reconnect on next call
26    }
27    Err(SdkError::NotConnected) => {
28        eprintln!("Not connected — reconnecting...");
29    }
30    Err(SdkError::StreamClosed) => {
31        eprintln!("Stream closed — resubscribe");
32    }
33    Err(e) => eprintln!("Unexpected error: {}", e),
34}

Error Handling — TypeScript

1import { SlipstreamClient } from "@allenhark/slipstream";
2
3try {
4    const result = await client.submitTransaction(txBytes);
5    console.log("Success:", result.signature);
6} catch (err: any) {
7    switch (err.code) {
8        case "AUTH":
9            console.error("Auth error — check your API key");
10            break;
11        case "INSUFFICIENT_TOKENS":
12            console.error("Not enough tokens");
13            const deposit = await client.getDepositAddress();
14            console.error("Deposit to:", deposit);
15            break;
16        case "RATE_LIMITED":
17            console.error("Rate limited:", err.message);
18            break;
19        case "TIMEOUT":
20            console.error("Request timed out");
21            break;
22        case "ALL_PROTOCOLS_FAILED":
23            console.error("All protocols failed");
24            break;
25        case "CONNECTION":
26            console.error("Connection error:", err.message);
27            break;
28        case "NOT_CONNECTED":
29            console.error("Not connected");
30            break;
31        default:
32            console.error("Unexpected error:", err);
33    }
34}

Error Handling — Python

1from allenhark_slipstream import SdkError
2
3try:
4    result = await client.submit_transaction(tx_bytes)
5    print(f"Success: {result.signature}")
6except SdkError as e:
7    if e.is_auth():
8        print(f"Auth error — check your API key: {e}")
9    elif e.is_insufficient_tokens():
10        print("Not enough tokens — deposit SOL")
11    elif e.is_rate_limited():
12        print(f"Rate limited: {e}")
13    elif e.is_timeout():
14        print("Request timed out")
15    elif e.is_connection():
16        print(f"Connection error: {e}")
17    else:
18        print(f"Error: {e}")

Retry Configuration

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

Config-Level Retries — Rust

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

Per-Request Retries — Rust

1let result = client.submit_transaction_with_options(&tx_bytes, &SubmitOptions {
2    max_retries: 5,
3    retry: Some(RetryOptions {
4        max_retries: 5,
5        backoff_base_ms: 100,
6        cross_sender_retry: true, // Try a different sender on retry
7    }),
8    ..Default::default()
9}).await?;

Backoff Strategies

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

Connection Events

Monitor connection state changes.

Events — Rust

1println!("Connected: {}", client.is_connected());
2
3let info = client.connection_info();
4println!("Session: {}, Protocol: {:?}", info.session_id, info.protocol);

Events — TypeScript

1client.on("connected", () => console.log("Connected!"));
2client.on("disconnected", () => console.log("Disconnected"));
3client.on("error", (err) => console.error("Error:", err));
4
5console.log("Connected:", client.isConnected());

Events — Python

1@client.on("connected")
2async def on_connected():
3    print("Connected!")
4
5@client.on("disconnected")
6async def on_disconnected():
7    print("Disconnected")
8
9@client.on("error")
10async def on_error(err):
11    print(f"Error: {err}")

Performance Metrics

Track success rates and latency.

Metrics — Rust

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

Metrics — TypeScript

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

Next Steps