# Diagnose errors

Identify the failing update hash and restore source locations with the matching build sourcemap.

## Diagnose in this order {#start}

1. **Identify the update** using `getUpdateMetadata().currentVersion` on the affected device; record time and native version.
2. **Collect the stack** from captured JS errors or your existing crash reporter, not just a screenshot.
3. **Find the matching map** from the exact `.ppk` build; a newly rebuilt map is not a substitute.
4. **Symbolicate and verify** the source locations, then fix and test a new release.

## Why it matters {#why}

The scariest OTA scenario: the update is already on user devices, a screen goes blank on some models, and all you have is "users say it won't open". Pakta builds a JS error reporting pipeline into the SDK: when an error occurs, it reports together with the **active update identity** (appKey, native package version, active update hash), so "which version is failing" becomes one queryable field.

## Automatic reporting {#automatic}

After initialization, the SDK chains into React Native's global `ErrorUtils` — it does not replace your existing handler, it runs after it:

- Uncaught JS exceptions are reported automatically;
- Reported payload: error message, JS stack, update identity and basic device info;
- Reporting shares the same service configuration as update telemetry.

To opt out of JS error reporting alone:

```tsx
const updateClient = new Pakta({
  appKey,
  disableErrorReporting: true, // disable JS error reporting only
  // disableTelemetry: true,   // also disable update lifecycle telemetry
});
```

## Manual capture {#capture}

Caught exceptions (for example ones you try/catch in your API layer) are not reported by default — submit them explicitly when they matter:

```tsx
// Reuse the existing client created outside the root component.

try {
  await riskyCheckout();
} catch (error) {
  client.captureException(error, { context: 'checkout' });
}
```

The context object is stored alongside the error — put the business identifiers you will want while debugging.

## Crash platform correlation {#crash-report}

Native crashes and ANRs live outside the JS pipeline — hand them to Sentry / Crashlytics, while Pakta injects the **active update identity** into those reports:

```tsx
import * as Sentry from '@sentry/react-native';
import { attachToSentry } from 'rn-update';

// Call after existing Sentry initialization, passing the reporter.
attachToSentry(Sentry);
```

Filter a Sentry board by `pakta.currentVersion` and you can answer "which hot update version do these crashes cluster on".

## Symbolication {#symbolicate}

`bundle` generates a sourcemap by default; archive it with `publish --sourcemap`, then turn production stacks back into source positions with the CLI:

```bash
pakta symbolicate stack.txt --platform android --hash <UPDATE_HASH>
```

Get `hash` from `getUpdateMetadata().currentVersion`; the final Hermes mapping is composed at bundle time automatically. See the [CLI](/docs/cli#diagnostics).

> [!IMPORTANT] Privacy boundary
> Never put tokens, passwords or personal information into error contexts or custom fields; reported fields are stored as-is on the server.

## If source locations are missing {#verify}

Check that `publish --sourcemap` archived successfully, the hash belongs to the failing update, and the platform matches. An embedded bundle has an empty currentVersion and needs its native-build mapping workflow. Without the original map, accurate source recovery is not guaranteed.
