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

# Error handling

> Handle bridge errors with typed error codes and recoverability metadata

All bridge errors are typed as `BridgeError` with machine-readable codes and recoverability metadata.

## The `BridgeError` class

```typescript theme={null}
import { BridgeError, BridgeErrorCode } from '@gbgplc-internal/ggo-native-bridge';

try {
  await bridge.request('camera.document.capture', data);
} catch (error) {
  if (error instanceof BridgeError) {
    console.log(error.code);          // BridgeErrorCode enum value
    console.log(error.message);       // Human-readable description
    console.log(error.recoverable);   // Can the user retry?
    console.log(error.correlationId); // Which request failed?
  }
}
```

## Error codes

| Code                | Meaning                                 | Recoverable | Recommended action                                      |
| ------------------- | --------------------------------------- | :---------: | ------------------------------------------------------- |
| `UNSUPPORTED`       | Host doesn't support this feature       |      No     | Fall back to web implementation or show "not available" |
| `PERMISSION_DENIED` | User denied a required permission       |     Yes     | Show permission explanation, offer retry                |
| `CANCELLED`         | User cancelled the operation            |     Yes     | Return to previous state, allow retry                   |
| `TIMEOUT`           | Host didn't respond in time             |     Yes     | Show timeout message, offer retry                       |
| `BUSY`              | Another native operation is in progress |     Yes     | Wait and retry, or queue the request                    |
| `INVALID_REQUEST`   | Request payload was malformed           |      No     | Fix the request data (developer error)                  |
| `INTERNAL_ERROR`    | Unexpected host error                   |      No     | Show generic error, log for debugging                   |
| `VERSION_MISMATCH`  | Protocol version incompatibility        |      No     | Update SDK or host app                                  |

## Handling patterns

There are three useful ways to react to a `BridgeError`: branch on the specific code, branch on the recoverable flag, or sidestep the error entirely by checking capabilities upfront. Pick whichever fits the call site — they compose naturally.

### Switch on error code

```typescript theme={null}
async function captureDocument() {
  try {
    return await bridge.request('camera.document.capture', {
      documentType: 'passport',
      side: 'front',
    }, { timeout: 120_000 });
  } catch (error) {
    if (!(error instanceof BridgeError)) throw error;

    switch (error.code) {
      case BridgeErrorCode.CANCELLED:
        return null;

      case BridgeErrorCode.PERMISSION_DENIED:
        showPermissionDialog('Camera access is required to capture your document.');
        return null;

      case BridgeErrorCode.TIMEOUT:
        showRetryDialog('The camera took too long to respond.');
        return null;

      case BridgeErrorCode.BUSY:
        await delay(1000);
        return captureDocument();

      case BridgeErrorCode.UNSUPPORTED:
        return captureWithWebCamera();

      default:
        showErrorDialog(`An error occurred: ${error.message}`);
        return null;
    }
  }
}
```

### Check recoverability

```typescript theme={null}
try {
  await bridge.request(action, data);
} catch (error) {
  if (error instanceof BridgeError) {
    if (error.recoverable) {
      showRetryButton(() => bridge.request(action, data));
    } else {
      showFallbackUI();
    }
  }
}
```

### Capability check before request

Avoid errors entirely by checking capabilities first:

```typescript theme={null}
import { CAPABILITY_IDS } from '@gbgplc-internal/ggo-native-bridge';

async function captureWithFallback() {
  const hasNativeCamera = bridge.hasCapability(CAPABILITY_IDS.CAMERA_DOCUMENT);

  if (hasNativeCamera) {
    try {
      return await bridge.request('camera.document.capture', data);
    } catch (error) {
      if (error instanceof BridgeError && !error.recoverable) {
        return captureWithWebCamera();
      }
      throw error;
    }
  }

  return captureWithWebCamera();
}
```

## Discovery errors

`discoverCapabilities()` can fail if the host doesn't respond. The React `<BridgeProvider>` handles this gracefully — `capabilitiesReady` is still set to `true`, capabilities remain empty, and the app continues normally.

If using the core library directly:

```typescript theme={null}
try {
  await bridge.discoverCapabilities(5_000);
} catch (error) {
  console.warn('Capability discovery failed:', error);
}

// hasCapability() will return false for all capabilities
```

## Request errors vs. response errors

There are two distinct error paths:

1. **Transport-level errors** — the request never reaches the host or the response is lost (e.g., `TIMEOUT`)
2. **Host-level errors** — the host received the request but returned an error (e.g., `PERMISSION_DENIED`, `UNSUPPORTED`, `CANCELLED`)

Both are surfaced as `BridgeError` instances.

## Logging and debugging

```typescript theme={null}
// Inspect the message log after an error
const log = bridge.getMessageLog();
const recentMessages = log.slice(-10);
console.log('Recent messages:', JSON.stringify(recentMessages, null, 2));

// Set up real-time logging
bridge.onMessageLog((message, direction) => {
  console.log(`[${direction}] ${message.type}: ${JSON.stringify(message.payload)}`);
});
```
