This page provides troubleshooting help and answers to frequently-asked questions about using Crashlytics. If you can't find what you're looking for or need additional help, contact Firebase support.
General troubleshooting/FAQ
You might notice two different formats for issues listed in your Issues table in the Firebase console. And you might also notice a feature called "variants" within some of your issues. Here's why!
In early 2023, we rolled out an improved analysis engine for grouping events as well as an updated design and some advanced features for new issues (like variants!). Check out our recent blog post for all the details, but you can read below for the highlights.
Crashlytics analyzes all the events from your app (like crashes, non-fatals, and ANRs) and creates groups of events called issues — all events in an issue have a common point of failure.
To group events into these issues, the improved analysis engine now looks at many aspects of the event, including the frames in the stack trace, the exception message, the error code, and other platform or error type characteristics.
However, within this group of events, the stack traces leading to the failure might be different. A different stack trace could mean a different root cause. To represent this possible difference within an issue, we now create variants within issues - each variant is a sub-group of events in an issue that have the same failure point and a similar stack trace. With variants, you can debug the most common stack traces within an issue and determine if different root causes are leading to the failure.
Here's what you'll experience with these improvements:
Revamped metadata displayed within the issue row
It's now easier to understand and triage issues in your app.Fewer duplicate issues
A line number change doesn't result in a new issue.Easier debugging of complex issues with various root causes
Use variants to debug the most common stack traces within an issue.More meaningful alerts and signals
A new issue actually represents a new bug.More powerful search
Each issue contains more searchable metadata, like exception type and package name.
Here's how these improvements are rolling out:
When we get new events from your app, we'll check if they match to an existing issue.
If there's no match, we'll automatically apply our smarter event-grouping algorithm to the event and create a new issue with the revamped metadata design.
This is the first big update that we're making to our event grouping. If you have feedback or encounter any issues, let us know by filing a report.
If you're not seeing breadcrumb logs (iOS+ | Android | Flutter | Unity), we recommend checking your app's configuration for Google Analytics. Make sure you meet the following requirements:
You've enabled Google Analytics in your Firebase project.
You've enabled Data sharing for Google Analytics. Learn more about this setting in Manage your Analytics data sharing settings
You've added to your app the Firebase SDK for Google Analytics: iOS+ | Android | Flutter | Unity.
This SDK must be added in addition to the Crashlytics SDK.You're using the latest Firebase SDK versions for all the products that you use in your app (iOS+ | Android | Flutter | Unity).
For Apple platforms and Android apps, especially check that you're using at minimum the following version of the Firebase SDK for Google Analytics:
iOS+ — v6.3.1+ (v8.9.0+ for macOS and tvOS) |Android — v17.2.3+ (BoM v24.7.1+) .
If you're not seeing velocity alerts, make sure that you're using the Crashlytics SDK v18.6.0+ (or Firebase BoM v32.6.0+).
If you're not seeing crash-free metrics (like crash-free users and sessions) or seeing unreliable metrics, check the following:
Make sure that you're using the Crashlytics SDK v18.6.0+ (or Firebase BoM v32.6.0+).
Make sure that your data collection settings aren't impacting the quality of your crash-free metrics:
If you enable opt-in reporting by disabling automatic crash reporting, crash information can only be sent to Crashlytics from users who have explicitly opted into data collection. Thus, the accuracy of crash-free metrics will be affected since Crashlytics only has crash information from these opted-in users (rather than all your users). This means that your crash-free metrics may be less reliable and less reflective of the overall stability of your app.
If you have automatic data collection disabled, you can use
sendUnsentReportsto send on-device cached reports to Crashlytics. Using this method will send crash data to Crashlytics, but not sessions data which causes the console charts to show low or zero values for crash-free metrics.
See Understand crash-free metrics.
Notes allow project members to comment on specific issues with questions, status updates, etc.
When a project member posts a note, it's labeled with the email of their Google Account. This email address is visible, along with the note, to all project members with access to view the note.
The following describes the access required to view, write, and delete notes:
Project members with any of the following roles can view and delete existing notes and write new notes on an issue.
- Project Owner or Editor, Firebase Admin, Quality Admin, or Crashlytics Admin
Project members with any of the following roles can view the notes posted on an issue, but they cannot delete or write a note.
- Project Viewer, Firebase Viewer, Quality Viewer, or Crashlytics Viewer
An issue has had a regression when you've previously closed the issue but Crashlytics gets a new report that the issue has re-occurred. Crashlytics automatically re-opens these regressed issues so that you can address them as appropriate for your app.
Here's an example scenario that explains how Crashlytics categorizes an issue as a regression:
- For the first time ever, Crashlytics gets a crash report about Crash "A". Crashlytics opens a corresponding issue for that crash (Issue "A").
- You fix this bug quickly, close Issue "A", and then release a new version of your app.
- Crashlytics gets another report about Issue "A" after you've closed the
issue.
- If the report is from an app version that Crashlytics knew about when you closed the issue (meaning that the version had sent a crash report for any crash at all), then Crashlytics won't consider the issue as regressed. The issue will remain closed.
- If the report is from an app version that Crashlytics did not know about when you closed the issue (meaning that the version had never sent any crash report for any crash at all), then Crashlytics considers the issue regressed and will re-open the issue.
When an issue regresses, we send a regression detection alert and add a regression signal to the issue to let you know that Crashlytics has re-opened the issue. If you don't want an issue to re-open due to our regression algorithm, "mute" the issue instead of closing it.
If a report is from an old app version that had never sent any crash reports at all when you closed the issue, then Crashlytics considers the issue regressed and will re-open the issue.
This situation can happen in the following situation: You've fixed a bug and released a new version of your app, but you still have users on earlier versions without the bug fix. If, by chance, one of those earlier versions had never sent any crash reports at all when you closed the issue, and those users start encountering the bug, then those crash reports would trigger a regressed issue.
If you don't want an issue to re-open due to our regression algorithm, "mute" the issue instead of closing it.
If your project uses Crashlytics alongside the Google Mobile Ads SDK,
it's likely that the crash reporters are interfering when
registering exception handlers. To fix the issue, turn off crash reporting in
the Mobile Ads SDK by calling disableSDKCrashReporting.
After you link Crashlytics to BigQuery, new datasets you create are automatically located in the United States, regardless of the location of your Firebase project.
Platform-specific support
The following sections provide support for platform-specific troubleshooting and FAQ: iOS+ | Android | Unity.
Apple platforms support
To upload your project's dSYMs and get verbose output, check the following:
Make sure your project's build phase contains the Crashlytics run script, which allows Xcode to upload your project's dSYMs at build time (read Initializing Crashlytics for instructions on adding the script). After updating your project, force a crash and confirm that the crash appears in the Crashlytics dashboard.
If you see a "Missing dSYM" alert in the Firebase console, check Xcode to make sure it's properly producing dSYMs for the build.
If Xcode is properly producing dSYMs, and you're still seeing missing dSYMs, it's likely the run script tool is getting stuck while uploading the dSYMs. In this case, try each of the following:
Make sure you're using the latest version of Crashlytics.
Upload the missing dSYM files manually:
- Option 1: Use the console-based "Drag and Drop" option in the dSYMs tab to upload a zip archive containing the missing dSYM files.
- Option 2: Use the
upload-symbolsscript to upload the missing dSYM files, for the provided UUIDs in the dSYMs tab.
If you continue to see missing dSYMs, or uploads are still unsuccessful, contact Firebase Support and be sure to include your logs.
If your stack traces seem to be poorly symbolicated, check the following:
If frames from your app's library lack references to your app's code, make sure that
is not set as a compilation flag.-fomit-frame-pointerIf you see several
(Missing)frames for your app's library, check if there are optional dSYMs listed as missing (for the affected app version) in the Crashlytics dSYMs tab of the Firebase console. If so, follow the "Missing dSYM alert" troubleshooting step in the dSYMs are missing/not uploading FAQ on this page. Note that uploading these dSYMs won't symbolicate crashes that have already occurred, but this will help ensure symbolication for future crashes.
Yes, you can implement Crashlytics in macOS and tvOS projects. Make sure to include v8.9.0+ of the Firebase SDK for Google Analytics so that crashes will have access to metrics collected by Google Analytics (crash-free users, latest release, velocity alerts, and breadcrumb logs).
You can now report crashes for multiple apps in a single Firebase project, even when the apps are built for different Apple platforms (for example, iOS, tvOS, and Mac Catalyst). Previously, you needed to separate the apps into individual Firebase projects if they contained the same bundle ID.
Android support
Crashlytics supports ANR reporting for Android apps from devices that run Android 11 and higher. The underlying API that we use to collect ANRs (getHistoricalProcessExitReasons) is more reliable than SIGQUIT or watchdog-based approaches. This API is available only on Android 11+ devices.
If some of your ANRs are missing their BuildIds, troubleshoot as follows:
Make sure that you're using an up-to-date Crashlytics Android SDK and Crashlytics Gradle plugin version.
If you're missing
BuildIds for Android 11 and some Android 12 ANRs, then it's likely that you're using an out-of-date SDK, Gradle plugin, or both. To properly collectBuildIds for these ANRs, you need to use the following versions:- Crashlytics Android SDK v18.3.5+ (Firebase BoM v31.2.2+)
- Crashlytics Gradle plugin v2.9.4+
Check if you're using a non-standard location for your shared libraries.
If you're only missing
BuildIds for your app’s shared libraries, it's likely that you're not using the standard, default location for shared libraries. If this is the case, then Crashlytics might not be able to locate the associatedBuildIds. We recommend that you consider using the standard location for shared libraries.Make sure that you're not stripping
BuildIds during the build process.Note that the following troubleshooting tips apply to both ANRs and native crashes.
Check if the
BuildIds exist by runningreadelf -non your binaries. If theBuildIds are absent, then add-Wl,--build-idto the flags for your build system.Check that you're not unintentionally stripping the
BuildIds in an effort to reduce your APK size.If you keep stripped and unstripped versions of a library, make sure to point to the correct version in your code.
There can be a mismatch between the count of ANRs between Google Play and Crashlytics. This is expected due to the difference in the mechanism of collecting and reporting ANR data. Crashlytics reports ANRs when the app next starts up, whereas Android Vitals sends ANR data after the ANR occurs.
Additionally, Crashlytics only displays ANRs that occur on devices running Android 11+, compared to Google Play which displays ANRs from devices with Google Play services and data collection consent accepted.
When an app uses an obfuscator that doesn't expose the file extension,
Crashlytics generates each issue with a .java file extension by default.
So that Crashlytics can generate issues with the correct file extension, make sure your app uses the following setup:
- Uses Android Gradle 4.2.0 or higher
- Uses R8 with obfuscation turned on. To update your app to R8, follow this documentation.
Note that after updating to the setup described above, you might start seeing
new .kt issues that are duplicates of existing .java issues. See the
FAQ to learn more about that circumstance.
Starting in mid-December 2021, Crashlytics improved support for applications that use Kotlin.
Until recently, the available obfuscators did not expose the file extension, so
Crashlytics generated each issue with a .java file extension by default.
However, as of Android Gradle 4.2.0, R8 supports file extensions.
With this update, Crashlytics can now determine if each class used within
the app is written in Kotlin and include the correct filename in the issue
signature. Crashes are now correctly attributed to .kt files (as appropriate)
if your app has the following setup:
- Your app uses Android Gradle 4.2.0 or higher.
- Your app uses R8 with obfuscation turned on.
Since new crashes now include the correct file extension in their issue
signatures, you might see new .kt issues that are actually just duplicates of
existing .java-labeled issues. In the Firebase console, we try to identify
and communicate to you if a new .kt issue is a possible duplicate of an
existing .java-labeled issue.
If you see the following exception, it's likely you're using a version of DexGuard that's incompatible with the Firebase Crashlytics SDK:
java.lang.IllegalArgumentException: Transport backend 'cct' is not registered
This exception does not crash your app but prevents it from sending crash reports. To fix this:
Make sure you're using the latest DexGuard 8.x release. The latest version contains rules that are required by the Firebase Crashlytics SDK.
If you don't want to change your DexGuard version, try adding the following line to your obfuscation rules (in your DexGuard config file):
-keepresourcexmlelements manifest/application/service/meta-data@value=cct
Android-NDK specific support
LLVM and GNU toolchains have distinct defaults and treatments for the read-only segment of your app's binaries, which may generate inconsistent stack traces in the Firebase console. To mitigate this, add the following linker flags to your build process:
If you're using the
lldlinker from the LLVM toolchain, add:-Wl,--no-rosegmentIf you're using the
ld.goldlinker from the GNU toolchain, add:-Wl,--rosegment
If you're still seeing stack trace inconsistencies (or if neither flag is pertinent to your toolchain), try adding the following to your build process instead:
-fno-omit-frame-pointer
The Crashlytics plugin bundles a
customized Breakpad symbol file generator.
If you prefer to use your own binary for generating Breakpad symbol files (for
example, if you prefer to build all native executables in your build chain from
source), use the optional symbolGeneratorBinary extension property to specify
the path to the executable.
You can specify the path to the Breakpad symbol file generator binary in one of two ways:
Option 1: Specify the path via the
firebaseCrashlyticsextension in yourbuild.gradlefileAdd the following to your app-level
build.gradle.ktsfile:Gradle plugin v3.0.0+
android { buildTypes { release { configure<CrashlyticsExtension> { nativeSymbolUploadEnabled = true // Add these optional fields to specify the path to the executable symbolGeneratorType = "breakpad" breakpadBinary = file("/PATH/TO/BREAKPAD/DUMP_SYMS") } } } }
lower plugin versions
android { // ... buildTypes { // ... release { // ... firebaseCrashlytics { // existing; required for either symbol file generator nativeSymbolUploadEnabled true // Add this optional new block to specify the path to the executable symbolGenerator { breakpad { binary file("/PATH/TO/BREAKPAD/DUMP_SYMS") } } } } }
Option 2: Specify the path via a property line in your Gradle properties file
You can use the
com.google.firebase.crashlytics.breakpadBinaryproperty to specify the path to the executable.You can manually update your Gradle properties file or update the file via the command line. For example, to specify the path via the command line, use a command like the following:
./gradlew -Pcom.google.firebase.crashlytics.symbolGenerator=breakpad \ -Pcom.google.firebase.crashlytics.breakpadBinary=/PATH/TO/BREAKPAD/DUMP_SYMS \ app:assembleRelease app:uploadCrashlyticsSymbolFileRelease
The Firebase Crashlytics NDK does not support ARMv5 (armeabi). Support for this ABI was removed as of NDK r17.
Unity support
If you're using Unity IL2CPP and you're seeing unsymbolicated stack traces, then try the following:
Make sure that you're using v8.6.1 or higher of the Crashlytics Unity SDK.
Make sure that you're set up for and running the Firebase CLI
crashlytics:symbols:uploadcommand to generate and upload your symbol file.You need to run this CLI command each time that you create a release build or any build for which you want to see symbolicated stack traces in the Firebase console. Learn more in Get readable crash reports.
Yes, Crashlytics can display symbolicated stack traces for your apps that use IL2CPP. This capability is available for apps released on either Android or Apple platforms. Here's what you need to do:
Make sure that you're using v8.6.0 or higher of the Crashlytics Unity SDK.
Complete the necessary tasks for your platform:
For Apple platform apps: No special actions are needed. For Apple platform apps, the Firebase Unity Editor plugin automatically configures your Xcode project to upload symbols.
For Android apps: Make sure that you're set up for and running the Firebase CLI
crashlytics:symbols:uploadcommand to generate and upload your symbol file.You need to run this CLI command each time that you create a release build or any build for which you want to see symbolicated stack traces in the Firebase console. Learn more in Get readable crash reports.
Reporting uncaught exceptions as fatals
Crashlytics can report uncaught exceptions as fatals (starting with v10.4.0 of the Unity SDK). The following FAQs help to explain the rationale and best practices for using this feature.
By reporting uncaught exceptions as fatals, you get a more realistic indication of what exceptions may result in the game being unplayable – even if the app continues to run.
Note that if you start reporting fatals, your crash-free users (CFU) percentage will likely decrease, but the CFU metric will be more representative of the end-users' experiences with your app.
In order for Crashlytics to report an uncaught exception as fatal, both of the following two conditions must be met:
During initialization in your app, the
ReportUncaughtExceptionsAsFatalproperty must be set totrue.Your app (or an included library) throws an exception that isn't caught. An exception that's created, but not thrown, is not considered uncaught.
When you start getting reports of your uncaught exceptions as fatals, here are some options for handling these uncaught exceptions:
- Consider how you can start catching and handling these uncaught exceptions.
- Consider different options for logging exceptions to the Unity debug console and to Crashlytics.
Catch and handle thrown exceptions
Exceptions are created and thrown to reflect unexpected or exceptional states. Resolving the issues reflected by a thrown exception involves returning the program to a known state (a process known as exception handling).
It's best practice to catch and handle all foreseen exceptions unless the program cannot be returned to a known state.
To control which sorts of exceptions are caught and handled by what code,
wrap code that might generate an exception in a try-catch block.
Make sure that the conditions in the catch statements are as narrow as
possible to handle the specific exceptions appropriately.
Log exceptions in Unity or Crashlytics
There are multiple ways to record exceptions in Unity or Crashlytics to help debug the issue.
When using Crashlytics, here are the two most common and recommended options:
Option 1: Print in the Unity console, but don't report to Crashlytics, during development or troubleshooting
- Print to the Unity console using
Debug.Log(exception),Debug.LogWarning(exception), andDebug.LogError(exception)which print the contents of the exception to the Unity console and don't re-throw the exception.
- Print to the Unity console using
Option 2: Upload to Crashlytics for consolidated reporting in the Crashlytics dashboard for the following situations:
- If an exception is worth logging to debug a possible subsequent
Crashlytics event, then use
Crashlytics.Log(exception.ToString()). - If an exception should still be reported to Crashlytics despite
being caught and handled, then use
Crashlytics.LogException(exception)to log it as a nonfatal event.
- If an exception is worth logging to debug a possible subsequent
Crashlytics event, then use
However, if you want to manually report a fatal event to Unity Cloud
Diagnostics, you can use Debug.LogException. This option prints the exception
to the Unity console like Option 1, but it also throws the exception
(whether or not it has been thrown or caught yet). It throws the error
nonlocally. This means that even a surrounding Debug.LogException(exception)
with try-catch blocks still results in an uncaught exception.
Therefore, call Debug.LogException if and only if you want to do all of
the following:
- To print the exception to the Unity console.
- To upload the exception to Crashlytics as a fatal event.
- To throw the exception, have it be treated as an uncaught exception, and have it be reported to Unity Cloud Diagnostics.
Note that if you want to print a caught exception to the Unity console and upload to Crashlytics as a nonfatal event, do the following instead:
try
{
methodThatThrowsMyCustomExceptionType();
}
catch(MyCustomExceptionType exception)
{
// Print the exception to the Unity console at the error level.
Debug.LogError(exception);
// Upload the exception to Crashlytics as a non-fatal event.
Crashlytics.LogException(exception); // not Debug.LogException
//
// Code that handles the exception
//
}