Skip to content

Symbolicating crash reports with dSYMs

View Markdown

When Xcode builds your app for distribution, it strips debug symbols from the binary to reduce file size. These symbols are saved separately in a .dSYM bundle alongside your build. Without uploading these bundles to Honeybadger, crash reports will show raw memory addresses instead of the function names, file names, and line numbers you need to diagnose the crash.

Uploading dSYMs lets Honeybadger display fully symbolicated stack traces like:

triggerExceptionCrash() ViewController.swift:42
AppDelegate.application AppDelegate.swift:18

No SDK configuration is needed for symbolication: every crash report already includes the metadata of each binary image loaded in the crashed process (its build UUID, load address, and architecture). Honeybadger matches this data to your uploaded dSYMs by build UUID, so all you need to do is upload the dSYMs for each build you distribute.

The Honeybadger SDK ships with an upload script, bin/upload-dsyms.sh, which uploads all .dSYM bundles for a build to Honeybadger. It automatically reads DWARF_DSYM_FOLDER_PATH (which Xcode sets during a build), so no extra configuration is needed when run from a build phase. Store your API key in an Xcode build setting or environment variable rather than hardcoding it.

Add the script as a Run Script build phase so dSYMs upload automatically whenever you archive a build:

  1. In Xcode, select your app target and go to Build Phases.
  2. Click + and select New Run Script Phase.
  3. Drag the new phase to the end of the list, after Link Binary With Libraries, so it runs after Xcode has produced the dSYM for the build.
  4. Add the run script for your installation method (below).

CocoaPods — the script is installed with the pod, so reference it from ${PODS_ROOT}:

Terminal window
bash "${PODS_ROOT}/Honeybadger/bin/upload-dsyms.sh" --api-key "${HB_API_KEY}" --warn-only

Swift Package Manager — SPM does not install standalone scripts to a referenceable location. Download bin/upload-dsyms.sh from the SDK repository, add it to your project (e.g. at Scripts/upload-dsyms.sh), and reference it:

Terminal window
bash "${SRCROOT}/Scripts/upload-dsyms.sh" --api-key "${HB_API_KEY}" --warn-only

--warn-only makes the script exit 0 when one or more uploads fail (for example, on a transient network error), so a failed upload never fails your archive. Setup problems, such as a missing API key or a missing curl, zip, or python3, still exit nonzero so they aren’t hidden. Omit --warn-only in CI, where a nonzero exit on failed uploads is what you want.

To upload dSYMs manually or from a CI pipeline, run the script directly and pass the dSYM directory with --dsym-path:

Terminal window
bash /path/to/upload-dsyms.sh --api-key PROJECT_API_KEY --dsym-path /path/to/dSYMs/

The script uploads all .dSYM bundles found in the specified directory.

If your Honeybadger account is in our EU region, pass the EU endpoint with --endpoint wherever you run the script:

Terminal window
bash /path/to/upload-dsyms.sh --api-key PROJECT_API_KEY --endpoint "https://eu-api.honeybadger.io"

The endpoint is the base URL of the Honeybadger API, so --endpoint also works for routing uploads through a proxy. Note that this only affects dSYM uploads; the SDK’s error-reporting endpoint is configured separately.

If you configure a revision in the SDK (the revision: parameter of configure), pass the same value to the upload script with --revision, so the uploaded dSYMs and the errors they symbolicate are tagged with the same release:

Terminal window
bash /path/to/upload-dsyms.sh --api-key PROJECT_API_KEY --revision "1.4.2"

Unlike source maps for JavaScript, dSYM-to-crash matching does not depend on the revision — it’s done by build UUID, so symbolication works with or without one. Revision is purely for release tracking.