Describe your environment
- Android Studio version: Narwhal | 2025.1
- Firebase Component: Crashlytics NDK (gradle plugin + buildtools)
- Component version:
com.google.firebase:firebase-crashlytics-gradle:3.0.7 (also reproducible on 3.0.6), AGP 8.x, Gradle 8.13, JDK 17
Describe the problem
I have uploadCrashlyticsSymbolFile<Variant>Release set to run after bundle<Variant>Release (was necessary since the plugin does not auto-upload #7582).
While uploading the symbols, hit a server error :
> java.io.IOException: Unknown error while sending file, check network [/<repo path>/build/crashlytics/<flavor>Release/nativeSymbols/<upload artifact>.gz; response: 503 HTTP/1.1 503 Service Unavailable]
I retried and it failed again with error :
> java.io.FileNotFoundException: /<repo path>/build/crashlytics/<flavor>Release/nativeSymbols/<same upload artifact>.gz (No such file or directory)
I then ran rm -rf ./build/crashlytics which then completed successfully.
Steps to reproduce:
-
Set finalizedBy uploadCrashlyticsSymbolFile<Variant>Release on bundle<Variant>Release:
tasks.configureEach { task ->
def m = task.name =~ /^bundle(.+)Release$/
if (m) task.finalizedBy("uploadCrashlyticsSymbolFile" + m[0][1] + "Release")
}
-
Run ./gradlew bundle<Variant>Release which hits 503 from upload task.
-
Without making any change, rerun the same command
Relevant Code:
-
No try/finally in FirebaseSymbolFileService.uploadNativeSymbolFile
(source).
gZippedSymbolFile.delete() is sequential code after webApi.uploadFile() — when uploadFile
throws on a 503, the .gz is never deleted and is left as an orphan in the output directory.
-
No try/finally in Buildtools.uploadNativeSymbolFiles
(source).
symbolFile.delete() also does not run on exception, and the for-loop aborts on the first
failure — every .sym that hadn't yet been processed is also stranded.
-
No filter on dir.listFiles() in Buildtools.uploadNativeSymbolFiles
(source): the next run iterates every entry
in nativeSymbols/, including the orphan .gz. For an input named orphan.gz, the code computes
gZippedSymbolFile = parent + removeExtension("orphan.gz") + ".gz" = same path as the input,
and FileUtils.gZipFile(orphan.gz, orphan.gz) truncate-rewrites the file while a
FileInputStream on it is still open.
-
RestfulWebApi.uploadFile (source) makes a single attempt with no retry on 5xx, so a transient backend issue fails the build.
Workaround that I'm using to delete previous run's possible orphans :
tasks.matching { it.name.startsWith("uploadCrashlyticsSymbolFile") }.configureEach {
doFirst {
def dir = symbolFileDirectory.get().asFile
if (dir.exists()) {
dir.listFiles({ f -> !f.name.endsWith(".sym") } as FileFilter)
?.each { it.delete() }
}
}
}
Describe your environment
com.google.firebase:firebase-crashlytics-gradle:3.0.7(also reproducible on 3.0.6), AGP 8.x, Gradle 8.13, JDK 17Describe the problem
I have
uploadCrashlyticsSymbolFile<Variant>Releaseset to run afterbundle<Variant>Release(was necessary since the plugin does not auto-upload #7582).While uploading the symbols, hit a server error :
I retried and it failed again with error :
I then ran
rm -rf ./build/crashlyticswhich then completed successfully.Steps to reproduce:
Set finalizedBy
uploadCrashlyticsSymbolFile<Variant>Releaseonbundle<Variant>Release:Run
./gradlew bundle<Variant>Releasewhich hits 503 from upload task.Without making any change, rerun the same command
Relevant Code:
No
try/finallyinFirebaseSymbolFileService.uploadNativeSymbolFile(source).
gZippedSymbolFile.delete()is sequential code afterwebApi.uploadFile()— whenuploadFilethrows on a 503, the
.gzis never deleted and is left as an orphan in the output directory.No
try/finallyinBuildtools.uploadNativeSymbolFiles(source).
symbolFile.delete()also does not run on exception, and the for-loop aborts on the firstfailure — every
.symthat hadn't yet been processed is also stranded.No filter on
dir.listFiles()inBuildtools.uploadNativeSymbolFiles(source): the next run iterates every entry
in
nativeSymbols/, including the orphan.gz. For an input namedorphan.gz, the code computesgZippedSymbolFile = parent + removeExtension("orphan.gz") + ".gz"= same path as the input,and
FileUtils.gZipFile(orphan.gz, orphan.gz)truncate-rewrites the file while aFileInputStreamon it is still open.RestfulWebApi.uploadFile(source) makes a single attempt with no retry on 5xx, so a transient backend issue fails the build.Workaround that I'm using to delete previous run's possible orphans :