Fix “Crashlytics detected a missing
dSYM for version …” error by auto uploading dSYM files for Flutter apps

Yuichi Fujiki
5 min readMar 30, 2023

--

Issue

Occasionally one of our Flutter Firebase project sent errors like this. “Crashlytics detected a missing dSYM for version …

What is a dSYM file?

dSYM (short for “debugging symbols”) is a file format used on macOS and iOS operating systems to store debugging information. It provides some kind of mapping between the binary and the source code. Crashlytics, on receiving a crash log that only contains binary information, uses this dSYM information to rebuild the stack trace and show it in a nice format.

So, let’s upload it

On first Google search, I hit this official document, which describes the process to auto-upload the dSYM to Crashlytics every time we make a build. Great!! However, this documentation did NOT work for us.

  1. flutterfire configure did NOT create the build phase script to upload dSYM for some reason
  2. The manual process described here did not work either. My guess is it may not be up to date with the latest Crashlytics platform 🤷🏻‍♂️

Anyway, let me describe the process that worked for me at the current date (Mar 30, 2023).

EDIT: The project was using Firebase Apple SDK 10.3.0 at the moment of the article. A Github discussion thread suggests that there was an update on upload_symbolsscript in the SDK 10.7.0 and the official documentation should work with a minor modification. I haven’t tested this personally, but if that solves it, that would be the way to go!!

1. Enable DWARF dSYM for Debug build

First, we need to enable the generation of dSYM for a Debug build in Xcode. This part is easy. In your target’s Build Settings, select “DWARF with dSYM File” for all configurations. By default, it is “DWARF” only for Debug configurations.

2. Write a pre-build script to remove the previous dSYM file

There were some gotchas I faced next.

First, I couldn’t find the generated dSYM file after the build. If you build the iOS app using flutter ... command, the location of dSYM files is a little bit different compared to the location of them from the Xcode build.

Xcode build is going to generate dSYM files under something like this:

~/Library/Developer/Xcode/DerivedData/Runner-bkbcyuncwaxqtdccdnaqrpveayui/Build/Products/Debug-dev-iphonesimulator/

However, flutter build/run command will create dSYM files right under the corresponding Flutter project directory.

./build/ios/Debug-iphonesimulator/

It made me scratch my head for a while, but it actually makes our life easier once I know. The Xcode’s derived folder with cryptic UUID is not fun to explore.

Next, I noticed that my dSYM file is only created for the first time, but it doesn’t update from the next build. (The timestamp of the file doesn’t change) If I delete the dSYM file and rebuild it, then it works 😲😲😲 So, I made sure to do that in my pre-build script.

I made a build phase script named “[Crashlytics] Clear dSYM”, and placed it before “Compile Sources”

Inside it, I added a script like this

rm -rf $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME

Environment variable $DWARF_DSYM_FOLDER_PATH and $DWARF_DSYM_FILE_NAME are properly figured out, regardless of whether you build from Xcode or from flutter command.

3. Write a post-build script to upload dSYM

This is the last part and the meaty part. In the official document, it says to write a script like this.

Locate the Firebase App ID for your Apple app. Here are two different places where you can find this ID:

In the Firebase console, go to your settings > Project settings. Scroll down to the Your apps card, then click on your Firebase Apple App to view the app's information, including its App ID.
In your Flutter project's top-level directory, find your firebase_options.dart file. The Firebase App ID for your Apple app is labeled as GOOGLE_APP_ID.

This unfortunately didn't work for us. In fact, the Firebase Console shows a slightly different script.

Here, we still use upload-symbols command as in the official doc, but we specify the GoogleService-Info.plist file with -gsp flag and specify the dSYM file path as the main input.

To follow this, I made the “[Crashlytics] Upload dSYM” build phase script and placed it at the very bottom.

The script itself looks like this.

sleep 1 # Without this, there seems a chance that the script runs before dSYM generation is finished 
$PODS_ROOT/FirebaseCrashlytics/upload-symbols -gsp $PROJECT_DIR/$FIREBASE_PLIST_PATH -p ios $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME

I made $FIREBASE_PLIST_PATH as a user-defined variable in Xcode build settings. (It was necessary for us because we implement flavors. You may not need this one)

That’s it!! Add an artificial crash by adding the following call in your dart code (from button tap etc):

FirebaseCrashlytics.instance.crash();

Build/run, and voila!! You will see your crash log appear on your dashboard:

Better yet, you will never hear the “Crashlytics detected a missing dSYM for version” error again 🎉 🎊

Conclusion

It became a rather long post. I wrote this article because I didn’t find any comprehensive workaround for this issue.

Maybe for most people, flutterfire configure configures the environment nicely. But for the few people it didn’t work, you can follow my three steps.

  1. Enable DWARF dSYM for Debug build configuration
  2. Write a pre-build script to remove the previous dSYM file
  3. Write a post-build script to upload dSYM

Hopefully, this helps some Flutter/Firebase developers in the coming days!!

--

--

Yuichi Fujiki
Yuichi Fujiki

Written by Yuichi Fujiki

Technical director, Freelance developer, a Dad, a Quadriplegic, Life of Rehab

Responses (4)