2026-07-13
Stack Overflow: View Question
Tags: ios, debugging, crash-reports, kmp, compose
Score: 0 | Views: 57
The asker is shipping an iOS app built with Kotlin Multiplatform + Compose Multiplatform. They've wired up NSExceptionKt, Firebase Crashlytics, and Xcode's native crash tooling, yet: (a) many crashes never surface at all, and (b) the ones that do arrive with stack traces that are effectively unreadable — often just hex addresses or generic Kotlin/Native internals.
Why this is genuinely hard. A KMP iOS binary is Kotlin compiled through Kotlin/Native (LLVM) into an Objective-C framework. That means a crash can originate in three different worlds — Kotlin, Swift/ObjC, or the C runtime — and each has its own unwinding and symbolication story:
NSExceptions. Uncaught Kotlin throwables terminate the process via abort(), so Crashlytics sees a SIGABRT with no Kotlin frames unless something bridges them.0x0000000104abcd12 instead of MyViewModel.onClick.A direction toward a fix.
build/bin/iosArm64/releaseFramework/shared.framework.dSYM must be uploaded via upload-symbols (or the run-script phase) alongside your app's own dSYM. This alone fixes ~80% of "unreadable" traces.setUnhandledExceptionHook { throwable -> ... } in commonMain (or iOS-side) to forward the throwable to Crashlytics before the runtime aborts. Log throwable.getStackTrace() as a non-fatal so Firebase captures the Kotlin frames.NSExceptions with symbolicated traces — but it only helps for exceptions that actually cross the bridge. Pure-Kotlin crashes still need the hook above.freeCompilerArgs += ["-Xg0"] or ensure debug info is preserved (-Xadd-source-mapping).Gotchas. Bitcode is deprecated but if legacy settings strip symbols during App Store processing, dSYMs must come from App Store Connect, not your local build. Also, background-thread Kotlin crashes need the hook installed on that thread's context — the new memory model made this easier but it's still per-worker.
