boltZharp Docs
data_objectApp Telemetry

Readable stack traces

Production builds are minified, obfuscated or stripped, so their stack traces point at code nobody wrote. Upload what your build produces and Zharp shows errors with your original functions, files and lines — and groups them by those.

What to upload, per platform

PlatformWhat the build makesHow it gets to Zharp
BrowserSource mapsA bundler plugin (Vite, webpack, Rollup, esbuild, Next.js) or the CLI
Node.jsSource maps of bundled server codeThe same plugins or the CLI
Androidmapping.txt from R8/ProGuardThe Gradle plugin io.zharp.android-gradle
FlutterDart symbols from --split-debug-infozharp dart-symbols upload
iOSdSYMsAn Xcode Run Script build phase (or curl)
Python, Go, PHP—Nothing: their stacks are readable as sent

Once uploaded, an error is symbolicated as it arrives, before it is grouped into an issue: the issue page shows the original frames, with the code around each one where the source map includes the source, and a Raw view of the stack as it was sent.

How builds are matched

Every upload is filed under a debug ID — an identity of the exact build, not its release name. JavaScript gets a UUID per file, written into the file and its map by the plugin or CLI; Android gets a UUID per build from the Gradle plugin; Flutter and iOS use the build ID and Mach-O UUID their compilers already write. The SDK sends the IDs of the code in each error's stack, so the right files are found whatever URL, CDN or device the code ran on, and rebuilding the same release twice can't mix them up. A release on the upload is optional and only for your own filtering.

The upload key

  1. 1
    Create a key with artifacts:write

    Under Integrations & API → Main API keys, create a workspace key with the Build uploads scope (artifacts:write). This is a secret for your CI — not the zpk_ app key your SDK sends data with.

  2. 2
    Give it to your build

    Store it in your CI's secrets as ZHARP_AUTH_TOKEN. Never commit it, and never put it in an app. Without it, the plugins still prepare the build but upload nothing.

  3. 3
    Tell it which app

    Uploads go to one app, by its ID — the number in the app's dashboard URL — as app / --app or ZHARP_APP.

Seeing your uploads

  • The app's Build files tab lists them — name, kind, debug ID, release, size and when it was uploaded — and lets you delete one.
  • Build files are kept until you delete them, so errors from old builds stay readable. Deleting the app deletes them.
  • Uploading the same file for the same build again replaces it. Up to 200 MB a file.

Troubleshooting

A stack still minified or obfuscated? Check, in order:

  • Is it the first error of a new build? One that arrives before its upload can come in raw; it becomes readable when you open its issue, and the errors after it are readable as they arrive. Upload before you deploy to avoid it.
  • Did the upload run? Look for it in the app's Build files tab, and in the build log: a missing ZHARP_AUTH_TOKEN makes the plugins warn and skip the upload, a key without artifacts:write or a wrong app ID fails with what to fix.
  • Is it the same build? Matching is by debug ID, so the files you upload must come from the build you ship. JavaScript you deploy without running inject (or the plugin) has no debug ID; an Android build without the Gradle plugin has no UUID; a Flutter app built again after uploading has new symbols.
  • Is the SDK current? The SDK version that sends debug IDs is needed in the app. Old errors sent before it stay raw.
  • iOS: is Debug Information Format set to DWARF with dSYM File for Release? Without it there is no dSYM to upload.

Next