> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sportsxapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Handle errors and retries in the SportsX C# SDK

> Understand every typed exception STX.Sdk throws, how the built-in Polly retry policy works, and how to handle rate limits and session expiry correctly.

`STX.Sdk` throws typed exceptions for every error condition you need to handle in application code. Network blips and transient HTTP failures are retried automatically via Polly before an exception ever reaches your code, so the exceptions you catch represent genuine problems that require action.

## Exceptions

All `STX`-prefixed exceptions live in the `STX.Sdk.Exceptions` namespace.

| Exception                                  | When thrown                                                                                  | Recommended action                                            |
| ------------------------------------------ | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `STXWrongCredentialsException`             | Email or password rejected at login                                                          | Prompt the user for fresh credentials                         |
| `STXTokenExpiredException`                 | JWT expired; refresh token still valid                                                       | Call `STXTokenService.RefreshTokenAsync`                      |
| `STXSessionExpiredException`               | Both JWT and refresh token expired                                                           | Call `STXLoginService.LoginAsync` again                       |
| `STXCancelOnDisconnectNotEnabledException` | `ConfirmOrderAsync(cancelOnDisconnect: true)` called before joining `STXActiveOrdersChannel` | Join the channel first, or set `cancelOnDisconnect: false`    |
| `STXGeoComplyException`                    | Geo-compliance check failed                                                                  | User is outside a permitted jurisdiction — surface to your UI |
| `GraphQLHttpRequestException`              | Non-200 HTTP response after all retries exhausted                                            | Treat as a service outage; back off and retry later           |

## Handle authentication failures

```csharp theme={null}
try
{
    await login.LoginAsync(email, password);
}
catch (STXWrongCredentialsException)
{
    // Surface to UI: "Email or password is incorrect."
}
catch (STXGeoComplyException ex)
{
    // Surface to UI: "Trading isn't available in your region."
    _logger.LogWarning(ex, "Geo block on login");
}
```

## Handle session expiry in trading calls

If you are not using `keepSessionAlive: true`, wrap trading calls with a token-refresh retry to handle expiry gracefully:

```csharp theme={null}
async Task<T> WithSession<T>(Func<Task<T>> call)
{
    try
    {
        return await call();
    }
    catch (STXTokenExpiredException)
    {
        // Refresh token is still valid — exchange it for a new JWT
        await _tokens.RefreshTokenAsync();
        return await call();
    }
    catch (STXSessionExpiredException)
    {
        // Both tokens expired — full re-login required
        await _login.LoginAsync(_email, _password);
        return await call();
    }
}

var order = await WithSession(() =>
    _orders.ConfirmOrderAsync(price, qty, marketId, action, orderType));
```

<Tip>
  Using `keepSessionAlive: true` at login eliminates the need for this wrapper in long-running bots. `STXSessionBackgroundService` handles refresh automatically in the background.
</Tip>

## Automatic transient retries

Every GraphQL mutation runs through `STXGraphQLBaseService.SendMutationWithRetry`, which uses **Polly** with the following default policy:

* **Retry triggers**: `HttpRequestException`, `TaskCanceledException` (timeout), and 5xx responses.
* **Attempts**: 3 retries after the initial failure (4 total).
* **Backoff**: exponential — 200 ms, 400 ms, 800 ms.

You do not need to add your own retry around SDK calls. Doing so can amplify brief outages by turning a single transient failure into multiple redundant requests.

If the error persists after all built-in retries, a `GraphQLHttpRequestException` surfaces. Treat it as a service outage — back off and try again after a delay.

## Rate limits

The exchange rate-limits by IP and account. Bursty order placement can produce HTTP 429 responses.

<Warning>
  The SDK does **not** retry 429 responses automatically. Retrying a 429 makes the situation worse. If you see them, reduce your request rate or consolidate orders with `ConfirmOrdersAsync`.
</Warning>

## Debug logging

Enable `Debug`-level logging to inspect full GraphQL request and response bodies, including operation names, variables, and elapsed time. This is usually enough to determine whether an error is a transient network issue or a schema mismatch:

```csharp theme={null}
services.AddLogging(builder =>
    builder
        .SetMinimumLevel(LogLevel.Debug)
        .AddConsole());
```

## See also

* [Authentication](/sdks/csharp/authentication) — session management and `keepSessionAlive`
* [Trading](/sdks/csharp/trading) — `cancelOnDisconnect` and `STXCancelOnDisconnectNotEnabledException`
* [Configuration](/sdks/csharp/configuration) — logging setup
