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

# .NET SDK - Error Handling

> Exception hierarchy and when each exception is thrown in the .NET SDK.

The SDK distinguishes between two classes of failures:

1. **Initial sync failures** - surfaced as exceptions. The application context refuses to start with an empty cache.
2. **Background sync / SSE failures** - never thrown. They are logged via `INexusLogger.Error(...)`, and the existing cache continues to be served.

## Exception hierarchy

All SDK exceptions extend `NexusException`. A single `catch` clause covers everything:

```csharp theme={null}
try
{
    var client = await NexusClient.CreateAsync(config);
}
catch (NexusException ex)
{
    Console.Error.WriteLine($"Nexus failed: {ex.Message}");
    Console.Error.WriteLine($"Cause: {ex.InnerException?.Message}");
    Environment.Exit(1);
}
```

The full hierarchy:

```
Exception
└── NexusException                       (abstract base)
    ├── NexusInitException               (initial sync failure)
    ├── NexusUnauthorizedException       (HTTP 401)
    ├── NexusNotFoundException           (HTTP 404)
    ├── NexusRateLimitedException        (HTTP 429 write rate limit - v0.5.0)
    ├── NexusPublicKeyException          (public key tried to read a secret)
    └── NexusSecretNotFoundException     (key absent from cache)
```

## When each is thrown

| Exception                                         | Thrown by                                                                                   | When                                                                                                                                                                                         |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NexusInitException`                              | `CreateAsync()`                                                                             | The initial sync failed for any reason. `InnerException` carries the underlying cause (often `NexusUnauthorizedException` or a transport-level `HttpRequestException`).                      |
| `NexusUnauthorizedException`                      | `CreateAsync()`, `SyncAsync()`                                                              | Server returned HTTP 401 - invalid API key, slug/key mismatch, or revoked key.                                                                                                               |
| `NexusBillingException` *(v0.2.0)*                | `CreateAsync()`, `SyncAsync()`                                                              | Server returned HTTP 402 - tenant has invoices overdue by more than 14 days. The SDK halts background sync and serves the last cached snapshot; check `client.BillingOverdue` on the client. |
| `NexusNotFoundException`                          | `CreateAsync()`, `SyncAsync()`                                                              | Server returned HTTP 404 - unknown subdomain or missing endpoint.                                                                                                                            |
| `NexusRateLimitedException` *(v0.5.0)*            | `SetSecretAsync()`, `DeleteSecretAsync()`, `DeleteSecretVersionAsync()`                     | Server returned HTTP 429 - write rate limit exceeded on secret modification endpoints.                                                                                                       |
| `NexusPublicKeyException`                         | `GetSecretAsync()`, `SetSecretAsync()`, `DeleteSecretAsync()`, `DeleteSecretVersionAsync()` | The client was created with a public key. Thrown synchronously, before the network call.                                                                                                     |
| `NexusServiceKindMismatchException` *(v0.2.0)*    | `GetSecretAsync()`                                                                          | The service `kind` reported by the server is `"frontend"`. Frontend services must not hold secrets, regardless of key type.                                                                  |
| `NexusSecretNotFoundException`                    | `GetSecretAsync()`                                                                          | The requested key is not in the cache. The exception's `SecretKey` property carries the key that was requested.                                                                              |
| `NexusWIFNotConfiguredException` *(v0.2.0)*       | `CreateAsync()`                                                                             | `Wif.Enabled = true` but no usable workload-identity provider matched the running environment. Wrapped in `NexusInitException` on the initial connect.                                       |
| `NexusWIFTokenExchangeFailedException` *(v0.2.0)* | `CreateAsync()`, `SyncAsync()`                                                              | `POST /v1/auth/token-exchange` returned a non-2xx response. Wrapped in `NexusInitException` on the initial connect.                                                                          |
| `NexusSessionExpiredException` *(v0.2.0)*         | `SyncAsync()`                                                                               | The WIF session JWT has expired and the SDK could not refresh it.                                                                                                                            |
| `NexusAbAddonNotAvailableException` *(v0.3.0)*    | `EvaluateABAsync()`                                                                         | Server returned HTTP 403 - the AB Testing add-on is not active for this tenant.                                                                                                              |

## What is NOT thrown

* **Background syncs** - silently retried on the next TTL tick. Cache served.
* **SSE transport errors** - exponential backoff, 3-strike fallback to polling. No exception surfaces.
* **`304 Not Modified`** - treated as success; TTL reset.
* **Missing config / flag** - `GetConfig` returns `(null, false)`; `GetFlag` returns the `defaultValue`.

<Info>
  The asymmetry between secrets (throw) and configs/flags (sentinel) is deliberate: a missing secret usually means "you're misconfigured, fail fast", while a missing flag usually means "use the safe default and continue".
</Info>

## Failure scenarios

### Wrong API key

```csharp theme={null}
try
{
    await NexusClient.CreateAsync(new NexusConfig
    {
        BaseUrl = "https://blue-ocean-a5rx7.westyx.dev",
        ApiKey  = "wxs_typo",
    });
}
catch (NexusInitException ex) when (ex.InnerException is NexusUnauthorizedException)
{
    // Handle bad credentials specifically.
}
```

### Reading a secret with a public key

```csharp theme={null}
var client = await NexusClient.CreateAsync(new NexusConfig
{
    BaseUrl = "...",
    ApiKey  = "wxp_...",
});

await client.GetSecretAsync("DB_PASSWORD");
// throws NexusPublicKeyException - synchronously, no network call
```

### Reading a secret that doesn't exist

```csharp theme={null}
try
{
    await client.GetSecretAsync("does.not.exist");
}
catch (NexusSecretNotFoundException ex)
{
    Console.WriteLine($"Missing: {ex.SecretKey}");
}
```

## SSE-specific behaviour

SSE failures **never** propagate to your code. The SDK logs them at `Error` level and keeps the cache going via TTL polling.

```
nexus: SSE transport error (attempt 1/3)
nexus: SSE transport error (attempt 2/3)
nexus: SSE 3 consecutive transport errors - falling back to TTL polling
```

If you need to react to "live updates are no longer available", poll `client.IsStreamConnected` - it flips to `false` when the stream falls back.
