Skip to main content

Debug files & native symbolication

A release build of a mobile or native app doesn't ship its names. An iOS or Android NDK crash reports instruction addresses; an R8-minified Android app reports a.b.c.d. Debug files are what turn those back into your code — the native counterpart of source maps.

Errora applies them at ingest, before grouping, so issues group on real function names that stay stable across builds.

What gets resolved​

  • Native frames (iOS crashes, Android NDK) → function name, file and line. C++ and Swift names are demangled, and inlined frames are expanded into frames of their own.
  • Java/Kotlin frames from an R8/ProGuard build → original class, method, file and line, with inlined methods expanded. Obfuscated exception class names are restored too.
  • Profiles: iOS profile frames are symbolicated with dSYMs, and Android profile method names are remapped through the ProGuard mapping — see Profiling.

Supported formats​

FormatPlatformWhere it comes from
dSYM (Mach-O DWARF)iOS, macOSXcode, with Debug Information Format = DWARF with dSYM File
ELF (.so, unstripped)Android NDK, LinuxThe NDK build's intermediate, unstripped libraries
Breakpad (.sym)Any nativedump_syms
PDBWindowsThe MSVC linker
ProGuard/R8 mapping.txtAndroid (Java/Kotlin)app/build/outputs/mapping/<variant>/mapping.txt

How a file is matched​

Every file is identified by a debug id, never by name or release:

  • Native files carry one inside the binary (the Mach-O UUID, the ELF build id, the PDB signature, the Breakpad module id). The SDK reports the debug id of every image loaded in the crashed process, and each frame's address is resolved against the file with that id.
  • ProGuard mappings are matched by a UUID that the Gradle plugin stamps into the app and the SDK reports with each event.

So the file must come from the exact build that crashed. Rebuilding the same commit gives new debug ids, and the old crashes won't match the new files.

Uploading​

Use the official Sentry tooling, unchanged — Errora implements the upload endpoints sentry-cli talks to. Point it at Errora with four settings:

SettingValue
SENTRY_URLhttps://<your-errora-host>
SENTRY_AUTH_TOKENAn Errora personal access token (errora_pat_…)
SENTRY_ORGThe organization slug (from /organizations/<slug>/…)
SENTRY_PROJECTThe project slug

The same values go in a .sentryclirc (url, org, project, token) or the Gradle sentry {} block. The token's owner needs the member role or higher in the organization.

sentry-cli​

# dSYMs, ELF, Breakpad, PDB — point it at a file or a directory
sentry-cli debug-files upload path/to/build/

# ProGuard/R8 mapping
sentry-cli upload-proguard --uuid <uuid> app/build/outputs/mapping/release/mapping.txt

Per platform​

  • Android — the Sentry Android Gradle plugin uploads the mapping and NDK symbols on every release build and stamps the ProGuard UUID for you. See Android.
  • iOS — an Xcode Run Script build phase running sentry-cli debug-files upload, or fastlane's sentry_debug_files_upload. See iOS.

From the browser​

Settings → Debug files uploads a file by hand, and lists, downloads and deletes what's there. Native files carry their own debug id. For a ProGuard mapping, fill in the optional debug id field with the UUID your app reports, so the mapping matches its events.

Reading an issue with missing files​

A frame whose debug file is missing is kept, not dropped, and flagged as unsymbolicated. The issue page lists the missing debug ids — with the image or mapping each belongs to — so you know exactly which file to upload.

Debug files only apply to events that arrive after the upload: upload the file, then wait for the next occurrence.

Self-hosting​

SettingDefaultMeaning
DEBUG_FILES_STORAGEfilesystemfilesystem keeps files on disk under DEBUG_FILES_ROOT; s3 keeps them in an S3-compatible bucket
DEBUG_FILES_ROOTbackend/var/debug-filesWhere files live with filesystem storage. Must be a shared volume when ingest workers run on several hosts — or use s3
DEBUG_FILES_S3_BUCKET, DEBUG_FILES_S3_ENDPOINT_URL, DEBUG_FILES_S3_REGION—The bucket for s3 storage (any S3-compatible service)
DEBUG_FILES_S3_ACCESS_KEY, DEBUG_FILES_S3_SECRET_KEY—Its credentials — keep them in a secret
DEBUG_FILES_S3_PREFIXdebug-filesKey prefix inside the bucket
DEBUG_FILES_CACHE_DIRsystem temp dirWith s3, each worker keeps the files it symbolicates with here (no volume needed)
DEBUG_FILES_CACHE_MAX_BYTES2 GBSize of that cache; least recently used files go first
DEBUG_FILE_UPLOAD_MAX_BYTES500 MBCap on a single browser upload

With s3 the workers are stateless: nothing needs to be mounted, and a replaced pod re-downloads what it needs on first use.

Upload chunks left behind by sentry-cli are trimmed nightly.

Limitations​

  • Minidumps (Breakpad, Crashpad, sentry-native) are stack-walked on the server, as Sentry does, with rust-minidump's minidump-stackwalk (in the Docker image; set MINIDUMP_STACKWALK for a custom build). Upload the binaries' debug files so the walk can use their unwind information; without them it falls back to frame pointers and stack scanning, and each frame shows how it was found (context, cfi, fp, scan).
  • Swift names are demangled with the Swift runtime library (libswiftCore), which the Docker image includes; a self-built image without it shows Swift symbols mangled ($s7MyApp…). C++ is always demangled.
  • Frames without a line number (Android profiles) are resolved the way Sentry does: by the method's parameter types when the frame carries its signature, otherwise by name — so an obfuscated name that maps to several methods with the same parameters stays as-is.

Troubleshooting​

SymptomCause / fix
Frames still show addresses / a.b.cThe file for that exact build wasn't uploaded — compare the missing debug id on the issue with Debug files
A file is listed but still doesn't matchIt's from a different build (same version, rebuilt) — upload from the job that produced the shipped binary
NDK frames unresolvedYou uploaded stripped .so files — upload the unstripped ones from the build intermediates
ProGuard mapping uploaded by hand never matchesIts debug id isn't the UUID the app reports
sentry-cli uploads to sentry.ioSENTRY_URL / url isn't set
403 on uploadThe token's owner isn't a member of that organization