Skip to main content

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. Uses write(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.

AI features are opt-in

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:

  1. Fetches the suggested fix diff from the server.
  2. Creates a branch named swiftpatch/fix/<shortHash> in your configured repo.
  3. Applies the diff.
  4. Commits with a descriptive message (auto-fix: <rootCause>).
  5. Opens a draft PR via the GitHub App.
  6. 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

EventFires when
CRASH_DETECTEDNative signal handler fired.
SYNC_ERRORUpload-related error.
ROLLBACK_PRODCrash 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.