5 min read
Fix the flutterfire upload-crashlytics-symbols error in flutter build ipa
The flutterfire upload-crashlytics-symbols error breaks flutter build ipa with Swift Package Manager. Why the phase misses the script, and how to fix it.
By Yevhen Beshkarov
- troubleshooting
- firebase
- ios
flutter run works, flutter build ios works, and then flutter build ipa fails in the build phase that the FlutterFire CLI adds for Firebase Crashlytics. This flutterfire upload-crashlytics-symbols error says that the upload script of Crashlytics is missing. The script is on the disk, but when Xcode archives an app that uses Swift Package Manager, the phase looks for it in the wrong directory. The fix changes one path in the Xcode project, and you have to apply it again after every flutterfire configure.
"Could not find the Crashlytics upload symbols script" in flutter build ipa
The phase named FlutterFire: "flutterfire upload-crashlytics-symbols" uploads the dSYM files of the iOS app to Firebase Crashlytics. With Swift Package Manager, the archive stops in it:
Unhandled exception:
Exception: Could not find the Crashlytics upload symbols script at "/Users/<you>/Library/Developer/Xcode/DerivedData/Runner-<hash>/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run". This usually means CocoaPods or Swift Package Manager has not finished installing "FirebaseCrashlytics" yet, or it was installed to an unexpected location. Try cleaning and rebuilding the project.
#0 UploadCrashlyticsSymbols.run (package:flutterfire_cli/src/commands/upload_symbols.dart:368:7)
Command PhaseScriptExecution failed with a nonzero exit code
** ARCHIVE FAILED **I got it with flutterfire_cli 1.4.1, the latest version when I wrote this, Flutter 3.44.2 and Xcode 27. The message suggests cleaning and rebuilding. Flutter 3.44 keeps the Swift packages somewhere else, so the script will not turn up in DerivedData however often you clean.
When it fails: flutter build ipa, but not flutter run
You have this case when:
- the Firebase packages of the app come through Swift Package Manager, which Flutter 3.44 uses by default, and not through CocoaPods;
- flutterfire_cli 1.4.1 configured the app on a Mac (it adds the phase only on macOS);
flutter runandflutter build iossucceed, and the phase uploads the symbols;flutter build ipafails. A comment in the upstream issue reports the same for Product > Archive in Xcode.
If flutter run fails too, with ProcessException: No such file or directory, an older flutterfire_cli wrote the phase. That case has its own section below.
The fix for the flutterfire upload-crashlytics-symbols error
The phase has the path $BUILD_DIR/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run twice. Replace both with $SRCROOT/../build/ios/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run. In the directory of the app:
ruby -e 'f = ARGV[0]; s = File.exist?(f) ? File.binread(f) : ""; t = s.gsub("$BUILD_DIR/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run", "$SRCROOT/../build/ios/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run"); if t == s then puts "Nothing to fix in #{f}" else File.binwrite(f, t); puts "Fixed the Crashlytics phase in #{f}" end' ios/Runner.xcodeproj/project.pbxprojIt prints Fixed the Crashlytics phase in ios/Runner.xcodeproj/project.pbxproj, or Nothing to fix in ios/Runner.xcodeproj/project.pbxproj when the file has no such path, for example because you fixed it already. Nothing else in the project changes. You can make the same edit by hand in Xcode: the Runner target, Build Phases, the phase with the name above.
After that, flutter build ipa archives the app and the phase uploads the symbols. flutter run and flutter build ios work as before, because for them both paths are the same directory.
Two caveats:
flutterfire configurewrites the phase again when its script differs from the one it would write. Run the fix after everyflutterfire configure.- The new path assumes that Flutter builds into
build. If you changed that withflutter config --build-dir, the path is wrong for you. Flutter exportsFLUTTER_APPLICATION_PATHandFLUTTER_BUILD_DIRto the phase, so"${FLUTTER_APPLICATION_PATH}/${FLUTTER_BUILD_DIR}/ios/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run"should follow your setting. I have tried only the default.
Why the phase misses the Crashlytics upload script
The script of the phase looks for the upload script in four places, in this order:
$PODS_ROOT/FirebaseCrashlytics/run, for CocoaPods;$BUILD_DIR/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run;- the same
SourcePackagespath in the DerivedData directory of the project; - whatever
findturns up in$BUILD_DIRand in that DerivedData directory.
With Swift Package Manager, Flutter clones the packages of the app into build/ios/SourcePackages: it passes -clonedSourcePackagesDirPath to xcodebuild. For flutter run and flutter build ios it also passes BUILD_DIR=<app>/build/ios, so the second place has the script. For an archive it leaves BUILD_DIR alone, on purpose:
if (buildAction !=
XcodeBuildAction.archive) // dSYM files aren't copied to the archive if BUILD_DIR is set.
'BUILD_DIR=${globals.fs.path.absolute(buildDirectoryPath)}',So during flutter build ipa, $BUILD_DIR is the one Xcode picks:
~/Library/Developer/Xcode/DerivedData/Runner-<hash>/Build/Intermediates.noindex/ArchiveIntermediates/Runner/BuildProductsPathNone of the four places has the script. The phase hands flutterfire the DerivedData path of the third place, and that is the path in the error. The stable branch of Flutter had the same lines on the day I wrote this.
$SRCROOT is the ios directory of the app. $SRCROOT/../build/ios/SourcePackages is where Flutter put the packages, whatever $BUILD_DIR says.
ProcessException: No such file or directory with flutterfire_cli 1.4.0 or older
The phase that flutterfire_cli 1.4.0 and older versions write knows only CocoaPods and DerivedData. With Flutter 3.44 and Swift Package Manager it fails in every iOS build, flutter run included:
Unhandled exception:
ProcessException: No such file or directory
Command:
/Users/<you>/Library/Developer/Xcode/DerivedData/Runner-<hash>/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run --validate --flutter-project .../app_id_file.jsonActivating flutterfire_cli 1.4.1 does not fix it, because the old phase stays in the Xcode project. Activate it and configure the app again on a Mac, and the new phase replaces the old one:
dart pub global activate flutterfire_cli 1.4.1
flutterfire configureThen apply the fix above, for flutter build ipa.
Where the fix stands in flutterfire_cli
The upstream issue is invertase/flutterfire_cli#443, open since May 2026. Version 1.4.1, from August, added the lookup in $BUILD_DIR/SourcePackages, which covers flutter run and flutter build ios. The comments of the issue describe the archive case, the latest of them from the end of September. Two open pull requests change the lookup: #444 and #456. #428 is about the same phase in macOS apps, which I have not tried.
When a release with one of them is out, activate it and run flutterfire configure again. You will not need the fix from this post then.
How SMF applies the fix after flutterfire configure
I ran into this while building SMF, a free, open-source Flutter project generator. The launch post of SMF 0.3 says what it does today and what it can't do yet. For an app with Firebase Crashlytics, SMF runs this fix on macOS right after flutterfire configure, and puts the command into the README of the app for the next time you configure it yourself. Its CI archives a generated app with flutter build ipa --no-codesign and the fixed phase. Another job runs the real flutterfire configure and fails when the phase no longer has the path that the fix replaces, so a change upstream shows up as a red job. The Firebase guide of SMF has the details.