Guides
Crash reporting
Once Pharen.start() runs, crash reporting is on. Fatal crashes are captured at crash time, delivered on the next launch, and grouped into issues. Here's exactly what that means.
What Pharen captures
Installing the SDK installs two kinds of capture:
- Fatal crashes — uncaught Objective-C / Swift exceptions and the fatal POSIX signals (
SIGSEGV,SIGBUS,SIGILL,SIGFPE,SIGABRT,SIGTRAP). Each report carries the crash-site call stack, the loaded binary images (with their debug ids, for symbolication), and the identity of the build that died — its version and build number, read at crash time, not upload time. - Handled errors — anything you report yourself with
recordError(…), delivered through the normal event queue.
Pharen's handlers chain: any exception handler already installed still runs, and signals are re-raised to the default handler, so the operating system's own crash report is still produced. Pharen adds a report; it doesn't replace the platform's.
Reporting handled errors
For non-fatal failures — a caught exception, a degraded code path — record an error with as much or as little context as you have. Breadcrumbs are free-form strings that describe what led up to it:
Pharen.shared?.crashes.recordError(
"Checkout failed: payment gateway timeout",
stack: Thread.callStackSymbols,
severity: "error",
breadcrumbs: ["tapped_pay", "network_slow"]
)Handled errors are a telemetry-class event, so they follow the same consent gate and the same durable queue as everything else.
Delivery: next launch, duplicate-safe
A process that is crashing can't be trusted to make a network request on its way down. So Pharen writes a compact report to disk at crash time and uploads it the next time your app launches. The report file is the durable queue: it is deleted only when the server confirms a terminal outcome for it (accepted, duplicate, stripped, or rejected). A network failure leaves the file in place, and the next launch tries again.
Because a crashed app might not reopen for days or weeks, retries have to be safe to repeat. Each crash report gets a deterministic id derived from the report itself, so a retry after a lost response re-sends the same id. The server recognises it and answers duplicate — the crash is counted once, no matter how many launches it takes to get through.
Symbolication: upload your dSYMs
A crash from a release build arrives as memory addresses. To turn those into function names and line-adjacent frames, Pharen needs the build's dSYMs (debug symbol bundles). Crashes and symbols join on the binary's embedded debug id — never on a version string or a file path — so uploading is order-independent: symbols can arrive before or after the crash.
Upload symbols once per build, whichever way you ship:
- fastlane plugin —
pharen_releaseuploads every dSYM the archive produced, automatically. - Xcode run script — a build phase that uploads dSYMs on archive, no fastlane required.
- The release lane or the CLI directly (
pharen upload-symbols).
Grouping into issues
Raw crash events are collapsed into issues so a hundred reports of the same bug are one line, not a hundred. Grouping fingerprints the symbolicated stack — primarily the exception type and the top frames in your code — and deliberately ignores the volatile parts (memory addresses, line numbers, hashed paths) that change build to build. Stackless errors are grouped by a parameterized form of their message (numbers, ids, and quoted values normalized to placeholders).
Issues are tracked per release, so a bug that reappears in a build after the one where it was resolved is flagged as a regression rather than silently re-counted.