Skip to main content

Troubleshoot common Unity SDK issues

Use this guide to troubleshoot native crash capture on Apple and Android platforms and reporting limitations in WebGL builds.

Apple Native Crash Reporting​

Native Initialization Fails​

Check the Apple platform requirements and enable Capture Native Crashes. Install the complete SDK package so the managed code and native plugins match. Copying new managed files over an older macOS bundle or iOS bridge can prevent native initialization even when managed reports still arrive.

Inspect the player logs for the failed stage. For example, BT_MAC_ABI_MISMATCH or BT_IOS_ABI_MISMATCH indicates an incompatible bridge, while BT_MAC_LIBRARY_MISSING indicates a missing native library. Preserve the diagnostic code when contacting support; avoid sharing submission tokens or credential-bearing URLs.

After an installed native handler has been disabled, restart the application before enabling capture again. Also restart after an initialization failure that might have partially installed the handler. Calling Refresh() repeatedly does not retry a failed native initialization.

Legacy Mac Reports​

New macOS native reports use application-specific storage isolated from Unity's default PLCrashReporter cache. The flat native bundle removes the nested-framework symlink dependency. Replace the complete plugin when upgrading rather than applying a relinking workaround to an older bundle.

Recover Legacy Reports Before Launching the Upgraded Player

Reports left in the old shared PLCrashReporter cache are not migrated automatically. Preserve the crash payloads and accompanying metadata, and contact support for controlled recovery before launching the upgraded player. Do not delete unrelated cache data or rename pending reports as a runtime workaround.

If native capture is busy, close other instances of the same application, then restart the player before testing again. An application-specific lock prevents simultaneous instances from writing to the same pending-crash slot.

iOS Exports or Upgrade Tests Fail​

Set Player Settings > iOS > Target minimum iOS Version to 15.0 or newer. The postprocessor rejects an unsupported target rather than changing the setting. Keep the SDK's Editor postprocessor and plugin import settings in the project: the generated Xcode export links and embeds Backtrace automatically. Do not manually link or embed a second static CrashReporter runtime.

iOS retains its existing pending-report location. Test upgrades without clearing application data to verify delivery of a previously captured crash and preservation of its attachments.

For both Apple platforms, follow Verify Native Crash Reporting with the final signed player. A successful managed exception test or Xcode build does not establish native crash delivery. Relaunch after the crash, confirm receipt in Backtrace, and retain the matching application and native dSYMs for symbolication.

Android Native Crash Reporting​

For Android native crash capture requirements, APK and Android App Bundle support, failure behavior, and diagnostic codes, see Android Native Crash Integration for Unity.

Native Capture Does Not Initialize​

Native capture requires Android API level 21 or newer and a supported application binary interface (ABI): arm64-v8a, armeabi-v7a, or x86_64. Check the ABI of the running process, not only the device's supported architectures. A 32-bit process on a 64-bit device needs matching 32-bit libraries; 32-bit x86 does not support native capture.

Enable both Capture Native Crashes and Enable Database. Inspect the installed release Android application package (APK) or Android App Bundle installation, including its installed splits, for the matching Backtrace native libraries and Java crash-handler classes. An Editor test or a build archive alone does not verify the libraries installed on the device.

Android can load native libraries directly from an APK or an installed ABI split. The absence of an extracted library file does not prove that packaging failed, and forced native-library extraction is not required.

If release minification removes or renames the Java classes used by the bridge, apply the ProGuard Rules. Restart the application process after correcting native configuration or packaging before testing again.

Identify the Failed Stage​

Check the device logs for identifiers such as BT_UNITY_ANDROID_NATIVE_PREPARE_FAILURE for native setup or BT_HANDLER_LOAD_FAILURE for crash-handler library loading. These diagnostic codes identify failed stages; they are log identifiers, not report attributes. Managed reports can still arrive when native capture is unavailable.

Follow Verify Native Crash Reporting on the installed release build. Fatal native reports are uploaded after the application starts again. If a report arrives but its stack is not symbolicated, investigate matching debug symbols separately from capture and upload.

Low-Memory Warnings Do Not Produce Reports​

The Android low-memory callback annotates native state with memory.warning and memory.warning.date; it does not immediately create or submit a report. A low-memory warning or operating-system termination does not guarantee an out-of-memory report.

WebGL​

Stack Traces​

Stack trace availability in WebGL depends on Unity’s Exception Support setting:

Player Settings > Publishing Settings > WebGL > Exception Support

Exception SupportStack TracesLine Numbers
NoneNoNo
Explicitly Thrown Exceptions OnlyYes (thrown exceptions only)No
Full Without StacktracePartialNo
Full With StacktraceYesNo

Recommendation: Use Full With Stacktrace for the most complete reporting.

Why line numbers are missing on WebGL​

  • Unity WebGL uses IL2CPP to transpile C# to C++ and then to WebAssembly. Source-level C# line mapping is typically not preserved through this pipeline, so reports generally cannot include reliable C# line numbers. This is a Unity WebGL platform limitation.

Why some reports have no stack trace​

  • Some events may arrive without threads/frames when the runtime does not provide stack information at capture time. Common cases include:

    • Message-based logs such as Debug.LogError("..."): these are messages, not exceptions, so there may be no exception stack to attach.
    • Debug.LogException(exception): Unity may provide an exception object without stack information in WebGL, resulting in stackless reports.
    • Early startup errors: failures that occur before stack traces are attached (or before SDK initialization) can be captured without frames.

    Best practice: Prefer capturing real exceptions (not only messages) when you need stack traces.


Unity WebGL log-callback exceptions with empty stack traces​

The Backtrace Unity SDK listens to Application.logMessageReceived and Application.logMessageReceivedThreaded. Unity calls these handlers with a log message, a stackTrace string, and a LogType.

In WebGL/IL2CPP builds, Unity can emit an exception-like log event with a valid exception message but an empty stackTrace value. This can occur even when WebGL Exception Support is set to Full With Stacktrace and Stack Trace Logging is enabled.

When Unity supplies an empty callback stack, Backtrace cannot reconstruct the original managed C# throw-site stack from that callback alone. The SDK preserves the message, attributes, breadcrumbs, Unity log context, and stackless-capture diagnostics.

Newer SDK versions include diagnostic attributes for this path:

AttributeDescription
backtrace.unity.capture_pathSDK capture path, such as Application.logMessageReceived, Application.logMessageReceivedThreaded, or Debug.unityLogger.logHandler.LogException+Application.logMessageReceived.
backtrace.unity.log.typeUnity log type, such as Error or Exception.
backtrace.unity.log.stacktrace.emptyWhether Unity supplied an empty callback stackTrace string.
backtrace.unity.log.stacktrace.lengthLength of Unity's callback stackTrace string.
backtrace.unity.log.message.lengthLength of Unity's callback message.
backtrace.unity.log.thread.idThread id that processed the Unity log callback.
backtrace.unity.log.thread.is_mainWhether the Unity log callback was handled on the main thread.
backtrace.unity.stacktrace_log_type.errorRuntime Stack Trace Logging setting for LogType.Error.
backtrace.unity.stacktrace_log_type.exceptionRuntime Stack Trace Logging setting for LogType.Exception.
backtrace.unity.stack_sourceStack source selected by the SDK: original_exception_stacktrace, unity_log_callback_stacktrace, or unavailable.
backtrace.unity.report.frames.emptyWhether the final Backtrace report has zero managed frames.
backtrace.unity.stackless.reasonStackless classification when the final report has no frames.

Capturing original exceptions from Debug.LogException​

On WebGL, the SDK can observe exceptions passed through Debug.LogException(exception) by wrapping Debug.unityLogger.logHandler.

This is enabled automatically for WebGL builds:

configuration.UnityLogHandlerExceptionCapture =
BacktraceUnityLogHandlerExceptionCaptureMode.Automatic;

The SDK does not send directly from the log handler. It records the original exception object, forwards to Unity's original log handler, and waits for Unity's Application.logMessageReceived or Application.logMessageReceivedThreaded callback. When the callback arrives, the SDK chooses the best available stack source:

  1. Original exception stack trace, if present and parseable.
  2. Unity callback stackTrace, if present and parseable.
  3. No frames, with explicit stackless diagnostics, if neither exists.

This avoids creating SDK capture-time frames for stackless original exceptions.

When the original exception is observed, the SDK can add:

AttributeDescription
backtrace.unity.original_exception.sourceDebug.unityLogger.logHandler.
backtrace.unity.original_exception.typeOriginal exception type.
backtrace.unity.original_exception.stack_presentWhether the original exception object had a non-empty StackTrace.
backtrace.unity.original_exception.context_nameUnity context object name when available on the main thread.
backtrace.unity.original_exception.thread.idThread id where the original exception was observed.
backtrace.unity.original_exception.thread.is_mainWhether the original exception was observed on the main thread.
backtrace.unity.original_exception.stackless_reasonReason the original exception object did not contain a managed stack.

Optional WebGL JavaScript stack-at-capture​

The WebGL JavaScript stack fallback is disabled by default.

When enabled, the SDK captures a browser JavaScript stack at the time the SDK creates a stackless Unity log-callback report.

configuration.WebGLJavaScriptStackFallback =
BacktraceWebGLJavaScriptStackFallbackMode.StacklessUnityLogsOnly;

This stack is supplemental context only. It can contain browser, WebAssembly, Unity loader, or SDK callback frames. It is not the original managed C# throw-site stack and is not used as the faulting managed thread stack.

When a Unity WebGL report has no stack frames:

  1. Check backtrace.unity.capture_path.
  2. Check backtrace.unity.log.stacktrace.empty.
  3. Check backtrace.unity.stack_source.
  4. Check backtrace.unity.report.frames.empty.
  5. If backtrace.unity.stack_source=original_exception_stacktrace, the SDK used the original exception object's stack.
  6. If backtrace.unity.stack_source=unity_log_callback_stacktrace, the SDK used Unity's callback stack.
  7. If backtrace.unity.stack_source=unavailable, neither Unity's callback nor the observed original exception object provided a usable managed stack.

Native Crash Capture​

Native (unmanaged) crash capture is not supported on WebGL. WebGL executes inside the browser, so the SDK cannot intercept:

  • browser/tab crashes
  • WebAssembly runtime failures outside managed C#
  • native crash dumps (minidumps)

Only managed C# exceptions and Unity log events can be captured.


ANR (Application Not Responding) Detection​

ANR detection is not available on WebGL. Browser-hosted applications run on a single thread and do not expose platform watchdog mechanisms like native mobile/desktop environments.


Metrics (Error-Free Sessions & Users)​

Backtrace Metrics (Error-free sessions and Error-free users) are not supported on WebGL builds.


Application Lifecycle Constraints​

Browsers may terminate execution abruptly on:

  • page refresh / navigation
  • tab close
  • backgrounding (especially on mobile)

This can prevent in-flight uploads from completing. The SDK uses browser lifecycle signals where possible, but delivery during abrupt shutdown cannot be guaranteed.


Threading​

Unity WebGL runs effectively single-threaded. Background-thread behaviors available on native platforms are not available in WebGL builds, and some SDK operations use WebGL-safe alternatives.


Offline Persistence (Best Effort)​

Offline report storage is supported on WebGL, but it is subject to browser storage behavior and limits.

  • Storage quotas vary by browser/platform and may be enforced silently.
  • Private/incognito modes may restrict or disable persistence.
  • Users can clear site storage at any time.
  • Mobile browsers in particular can be more restrictive.

Offline persistence on WebGL should be treated as best-effort, not guaranteed.

If you need concrete sizing guidance for WebGL persistence, design reports to stay small and avoid large attachments where possible.


Persistent Identifiers​

A stable, persistent machine identifier cannot be guaranteed on WebGL because:

  • Browsers do not expose hardware identifiers
  • Browser storage can be cleared or restricted
  • Identifiers may change across sessions, browsers, or devices

Common scenarios​

WebGL reports are missing stack traces​

  • Confirm Exception Support is set to Full With Stacktrace.
  • Validate the event is captured as an exception (not only a message).
  • If events originate from Debug.LogException, try capturing the exception through Backtrace instead of relying on Unity’s log wrapper.
  • Inspect the report's backtrace.unity.stack_source attribute to confirm what stack the SDK used:
    • original_exception_stacktrace — the SDK used the original exception object's stack.
    • unity_log_callback_stacktrace — Unity supplied a non-empty callback stackTrace.
    • unavailable — neither Unity's callback nor the observed original exception object provided a usable managed stack.
  • When backtrace.unity.report.frames.empty=true, the final report has no managed frames; check backtrace.unity.stackless.reason for the classification.

WebGL reports show stacks but no line numbers​

This is expected on WebGL due to the IL2CPP → WebAssembly pipeline not preserving reliable source-level C# line mappings.

Offline reports are not replayed after reload​

  • Verify the browser is not in private/incognito mode.
  • Check whether site storage is blocked or cleared.
  • Test in a desktop browser first to isolate mobile storage constraints.

Metrics are not appearing for WebGL builds​

Metrics are not supported on WebGL.