fix: attach map_id to frames from stateless exception capture - #668
Conversation
captureExceptionStateless did not pass config.releaseIdentifier to ThrowableCoercer, so exceptions captured via the stateless path (including posthog-server's captureException) had no map_id on their stack frames and could not be symbolicated against uploaded ProGuard mappings. Thread releaseIdentifier through like the stateful captureException path does.
The core stateless fix alone did not help posthog-server users: the server config had no releaseIdentifier and asCoreConfig() never set one, so server captureException calls still emitted frames without map_id. Expose the setting (property + builder method), propagate it in asCoreConfig(), and add an end-to-end regression test asserting map_id on frames captured through the server API.
posthog-android Compliance ReportDate: 2026-08-03 22:29:59 UTC ✅ All Tests Passed!46/46 tests passed Capture Tests✅ 29/29 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
|
Reviews (1): Last reviewed commit: "feat(server): expose releaseIdentifier o..." | Re-trigger Greptile |
| /** | ||
| * Identifier attached as `map_id` to exception stack frames so PostHog can symbolicate | ||
| * them against an uploaded ProGuard/R8 mapping. It must match the map-id used when | ||
| * uploading the mapping, e.g. via | ||
| * `posthog-cli exp proguard upload --path "mapping.txt" --map-id "<releaseIdentifier>"`. | ||
| * Defaults to null (no `map_id` attached). | ||
| */ | ||
| public var releaseIdentifier: String? = null |
There was a problem hiding this comment.
not sure we need this in the server package, proguard/r8 are mainly android tools
you can minify server bundles with proguard but its not a common thing since the bundle lives in the server and its not exposed for reverse engineering
There was a problem hiding this comment.
hmm @marandaneto I was thinking that it's just general JVM SDK, so it can get shipped in desktop apps, CLI tools etc
it should technically be ~negligible cost here to pass the map_id (since captureException already does it too), but also related that I was looking into bringing more of the ET mechanism in "core" so we can expose it directly here too (i.e. #669 #670 and some upcoming draft ones I was testing/working on [extracted this one from #670 tbh]) 😁
There was a problem hiding this comment.
yeah its not a problem, but I doubt it'd be used
💡 Motivation and Context
captureExceptionStatelessdid not passconfig.releaseIdentifiertoThrowableCoercer, so exceptions captured through the stateless path never gotmap_idon their stack frames and could not be symbolicated against uploaded ProGuard/R8 mappings. The statefulcaptureExceptionpath already threads it through correctly.This also affected
posthog-server, whosecaptureExceptiondelegates to the stateless path — and additionally the serverPostHogConfighad no way to set areleaseIdentifierat all (asCoreConfig()never assigned one).Changes:
config.releaseIdentifiertoThrowableCoercerincaptureExceptionStateless, matching the stateful path.releaseIdentifieronposthog-server'sPostHogConfig(property + builder method) and propagate it inasCoreConfig().💚 How did you test it?
PostHogStatelessTestassertingmap_idappears on every frame whenreleaseIdentifieris set.PostHogTestasserting frames captured via the servercaptureExceptioncarrymap_id.PostHogConfigTestcases forasCoreConfig()propagation and the builder method.make test,make checkFormat, andapiCheckpass;apiDumpregenerated for the new server API.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file