Crash detection
Every crash in a Swiftpatch-managed app is captured, clustered, and — when F8 is enabled — root-caused and turned into a suggested fix by the AI PR agent.
The three layers
1. Native crash handler
An async-signal-safe native handler is installed during SDK load:
- iOS — C shim attached to
SIGSEGV,SIGABRT,SIGBUS,SIGILL,SIGFPE. Useswrite(2)with a pre-opened file descriptor — the only file-writing primitives guaranteed to be safe inside a signal handler. - Android — JNI breakpad-style handler installed when the native module loads.
The handler writes a minimal crash marker (release id + timestamp + signal number) to disk in microseconds, before the process dies. It does not attempt to collect a full stack trace — doing that from a signal handler is unreliable.
2. JS error capture
For JS-level errors (uncaught exceptions, unhandled promise rejections), the SDK installs lightweight error boundaries:
ErrorUtils.setGlobalHandler— catches uncaught JS exceptions.process.on('unhandledRejection', ...)— for promise rejections in non-React surfaces.
These surface via the error event on the bus. They count against the crash counter during the crash-detection window.
3. Boot counter + mount marker
The boot counter trips when the same bundle fails to reach markMounted() N times in a row. See Brick protection for the full algorithm.
Upload + clustering
On the next successful launch after a crash, the SDK uploads:
- The crash marker (release id, timestamp, signal).
- The JS error payload (message, stack trace if available, component stack from React error boundary).
- Device metadata (OS version, model, locale, free disk, free memory).
The server clusters crashes by:
- Normalizing the stack trace (strip line numbers, minification noise, device-specific paths).
- Grouping by the first N normalized frames.
- De-duping across devices so a single bug doesn't appear as thousands of unique crashes.
Each cluster gets a stable clusterId. The dashboard shows: first seen, last seen, unique device count, trend, affected releases.
AI root-cause analysis
For each cluster, Swiftpatch runs an AI analysis (Claude-powered) that produces:
- Root cause summary — one sentence explaining the bug.
- Suggested fix diff — a unified diff that, applied to your repo, is likely to resolve the crash.
- Confidence score — 0–100, based on how well the stack trace maps to identified code paths.
- Affected files + lines — so you can jump straight to the relevant code.
Analysis runs on-demand (when you open the cluster in the dashboard) or on every new cluster for customers on Pro plans.
F8 and root-cause analysis require an organization-level opt-in. Until enabled, Swiftpatch captures and clusters crashes, but does not run AI analysis or open PRs. See Data privacy.
F8 — the crash-to-PR agent
When you click "Open PR" on a crash cluster (or run swiftpatch pr <clusterId>), the F8 agent:
- Fetches the suggested fix diff from the server.
- Creates a branch named
swiftpatch/fix/<shortHash>in your configured repo. - Applies the diff.
- Commits with a descriptive message (
auto-fix: <rootCause>). - Opens a draft PR via the GitHub App.
- Sets the PR body to include the cluster id, affected releases, and fix summary.
Guardrails:
- Denylist of files the agent will not touch (lockfiles, CI configs, secret-related paths).
- Max 500 lines changed per PR.
- Max 10 PRs per repo per day.
- Always opens drafts — never auto-merges.
- The PR body links back to the cluster for context.
See the F8 PR agent guide.
Telemetry events
| Event | Fires when |
|---|---|
CRASH_DETECTED | Native signal handler fired. |
SYNC_ERROR | Upload-related error. |
ROLLBACK_PROD | Crash counter tripped, device reverted. |
These feed the dashboard's per-release crash-rate metric, which drives the auto-pause-on-crash-rate policy.
Integrating with existing crash reporters
Swiftpatch's crash detection is complementary to Sentry / Bugsnag / Crashlytics. It fires on the same underlying crashes but is focused on OTA-specific intelligence (which release, which slot, what to do about it).
Pipe Swiftpatch's lifecycle breadcrumbs into your existing reporter so your crash dashboards show the OTA context:
import * as Sentry from '@sentry/react-native';
import { installSentrySink } from '@swiftpatch/react-native/integrations/sentry';
installSentrySink(Sentry);
See Integrations.
Next steps
- Brick protection — how the crash handler ties into auto-rollback.
- F8 PR agent — install the GitHub App and open your first AI fix PR.
- Rollbacks — what happens when the crash counter trips.