From 2bbc5652176e01a82dc0200a6c95e0c8e5009979 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 16:12:41 -0700 Subject: [PATCH 01/12] Fix Storage putFile POSIX error 40 on iOS Simulator Disables background session on simulator for putFile to workaround a QUIC EMSGSIZE error, formats POSIX errors properly, and adds an integration test. --- .../Internal/StorageFetcherService.swift | 5 ++++ FirebaseStorage/Sources/StorageError.swift | 14 ++++++++--- .../Sources/StorageUploadTask.swift | 8 +++++-- .../Integration/StoragePOSIXErrorTest.swift | 23 +++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift diff --git a/FirebaseStorage/Sources/Internal/StorageFetcherService.swift b/FirebaseStorage/Sources/Internal/StorageFetcherService.swift index 6364efe3106..6ec9d8f3029 100644 --- a/FirebaseStorage/Sources/Internal/StorageFetcherService.swift +++ b/FirebaseStorage/Sources/Internal/StorageFetcherService.swift @@ -63,6 +63,11 @@ actor StorageFetcherService { if let _fetcherService { _fetcherService.testBlock = testBlock } + for (_, bucketMap) in fetcherServiceMap { + for (_, fetcherService) in bucketMap { + fetcherService.testBlock = testBlock + } + } } private var testBlock: GTMSessionFetcherTestBlock? diff --git a/FirebaseStorage/Sources/StorageError.swift b/FirebaseStorage/Sources/StorageError.swift index f3e02340a2d..aa91c8ebe8c 100644 --- a/FirebaseStorage/Sources/StorageError.swift +++ b/FirebaseStorage/Sources/StorageError.swift @@ -77,9 +77,17 @@ public let StorageErrorDomain: String = "FIRStorageErrorDomain" case 404: StorageError.objectNotFound( object: ref.path.object ?? "", serverError: errorDictionary ) - default: StorageError.unknown( - message: "Unexpected \(serverError.code) code from backend", serverError: errorDictionary - ) + default: + if serverError.domain == NSPOSIXErrorDomain { + StorageError.unknown( + message: "POSIX errno \(serverError.code) (\(String(cString: strerror(Int32(serverError.code)))))", + serverError: errorDictionary + ) + } else { + StorageError.unknown( + message: "Unexpected \(serverError.code) code from backend", serverError: errorDictionary + ) + } } return storageError as NSError } diff --git a/FirebaseStorage/Sources/StorageUploadTask.swift b/FirebaseStorage/Sources/StorageUploadTask.swift index 8ce55adba79..49849ed6312 100644 --- a/FirebaseStorage/Sources/StorageUploadTask.swift +++ b/FirebaseStorage/Sources/StorageUploadTask.swift @@ -112,9 +112,13 @@ import Foundation uploadFetcher.uploadFileURL = fileURL uploadFetcher.comment = "File UploadTask" - if !GULAppEnvironmentUtil.supportsBackgroundURLSessionUploads() { + #if targetEnvironment(simulator) uploadFetcher.useBackgroundSession = false - } + #else + if !GULAppEnvironmentUtil.supportsBackgroundURLSessionUploads() { + uploadFetcher.useBackgroundSession = false + } + #endif } uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryInterval diff --git a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift new file mode 100644 index 00000000000..419ff826081 --- /dev/null +++ b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift @@ -0,0 +1,23 @@ +import Foundation +@testable import FirebaseStorage +import GTMSessionFetcherCore +import XCTest + +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) +class StoragePOSIXErrorTest: StorageIntegrationCommon { + func testPutFileWithPOSIXError40() async throws { + let ref = storage.reference(withPath: "ios/public/testPOSIX40") + + let data = try XCTUnwrap("Hello".data(using: .utf8)) + let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) + let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") + try data.write(to: fileURL, options: .atomicWrite) + + do { + let metadata = try await ref.putFileAsync(from: fileURL) + XCTAssertEqual(metadata.size, Int64(data.count)) + } catch { + XCTFail("Unexpected failure: \(error)") + } + } +} From 8c7581e8845184b69459c3f595df5164c1012d90 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 16:15:31 -0700 Subject: [PATCH 02/12] style --- .../Tests/Integration/StoragePOSIXErrorTest.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift index 419ff826081..e7e5b9cb979 100644 --- a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift +++ b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift @@ -1,18 +1,22 @@ -import Foundation @testable import FirebaseStorage -import GTMSessionFetcherCore +import Foundation +#if COCOAPODS + import GTMSessionFetcher +#else + import GTMSessionFetcherCore +#endif import XCTest @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *) class StoragePOSIXErrorTest: StorageIntegrationCommon { func testPutFileWithPOSIXError40() async throws { let ref = storage.reference(withPath: "ios/public/testPOSIX40") - + let data = try XCTUnwrap("Hello".data(using: .utf8)) let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") try data.write(to: fileURL, options: .atomicWrite) - + do { let metadata = try await ref.putFileAsync(from: fileURL) XCTAssertEqual(metadata.size, Int64(data.count)) From 65e6f3e1f4457887097d0daed929fb000584217f Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 16:20:52 -0700 Subject: [PATCH 03/12] changelog --- FirebaseStorage/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FirebaseStorage/CHANGELOG.md b/FirebaseStorage/CHANGELOG.md index 4e70ab82bff..5a864d8f5fc 100644 --- a/FirebaseStorage/CHANGELOG.md +++ b/FirebaseStorage/CHANGELOG.md @@ -1,4 +1,7 @@ # Unreleased +- [fixed] Fixed an issue where `putFile` could fail on the iOS Simulator with `POSIX errno 40` + (`EMSGSIZE`) due to a QUIC bug in background sessions, and improved error formatting + for `NSPOSIXErrorDomain` errors. (#16351) - [fixed] Fixed a race condition in Storage task cancellation and improved Swift 6 strict concurrency compliance for `StorageTask`. (#16353) - [fixed] Fixed a crash that could occur when parsing malformed `gs://` URLs, and improved From 4cec04cc1aaf1a1168d8301bc6f71052b3bc0098 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 16:23:41 -0700 Subject: [PATCH 04/12] copyright --- .../Tests/Integration/StoragePOSIXErrorTest.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift index e7e5b9cb979..58225c7b058 100644 --- a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift +++ b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift @@ -1,3 +1,17 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + @testable import FirebaseStorage import Foundation #if COCOAPODS From c7e7a4c48fcc26c10e662994fe0a03734b35b777 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 16:48:47 -0700 Subject: [PATCH 05/12] review --- FirebaseStorage/Sources/StorageError.swift | 2 +- FirebaseStorage/Sources/StorageUploadTask.swift | 9 +++++---- .../Tests/Integration/StoragePOSIXErrorTest.swift | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/FirebaseStorage/Sources/StorageError.swift b/FirebaseStorage/Sources/StorageError.swift index aa91c8ebe8c..fd4693b1668 100644 --- a/FirebaseStorage/Sources/StorageError.swift +++ b/FirebaseStorage/Sources/StorageError.swift @@ -80,7 +80,7 @@ public let StorageErrorDomain: String = "FIRStorageErrorDomain" default: if serverError.domain == NSPOSIXErrorDomain { StorageError.unknown( - message: "POSIX errno \(serverError.code) (\(String(cString: strerror(Int32(serverError.code)))))", + message: "POSIX errno \(serverError.code) (\(String(cString: strerror(Int32(truncatingIfNeeded: serverError.code)))))", serverError: errorDictionary ) } else { diff --git a/FirebaseStorage/Sources/StorageUploadTask.swift b/FirebaseStorage/Sources/StorageUploadTask.swift index 49849ed6312..280f69d79e1 100644 --- a/FirebaseStorage/Sources/StorageUploadTask.swift +++ b/FirebaseStorage/Sources/StorageUploadTask.swift @@ -113,12 +113,13 @@ import Foundation uploadFetcher.comment = "File UploadTask" #if targetEnvironment(simulator) - uploadFetcher.useBackgroundSession = false + let supportsBackground = false #else - if !GULAppEnvironmentUtil.supportsBackgroundURLSessionUploads() { - uploadFetcher.useBackgroundSession = false - } + let supportsBackground = GULAppEnvironmentUtil.supportsBackgroundURLSessionUploads() #endif + if !supportsBackground { + uploadFetcher.useBackgroundSession = false + } } uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryInterval diff --git a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift index 58225c7b058..5e3eae9e6da 100644 --- a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift +++ b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift @@ -30,6 +30,9 @@ class StoragePOSIXErrorTest: StorageIntegrationCommon { let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") try data.write(to: fileURL, options: .atomicWrite) + defer { + try? FileManager.default.removeItem(at: fileURL) + } do { let metadata = try await ref.putFileAsync(from: fileURL) From a423ac078e9f2b292d36aea8a64d1eff831327ec Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 17:32:33 -0700 Subject: [PATCH 06/12] More tests --- .../Integration/StoragePOSIXErrorTest.swift | 8 +-- .../Tests/Unit/StoragePutFileTests.swift | 57 +++++++++++++++++++ FirebaseStorage/Tests/Unit/StorageTests.swift | 11 ++++ 3 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 FirebaseStorage/Tests/Unit/StoragePutFileTests.swift diff --git a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift index 5e3eae9e6da..9feb47e514d 100644 --- a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift +++ b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift @@ -34,11 +34,7 @@ class StoragePOSIXErrorTest: StorageIntegrationCommon { try? FileManager.default.removeItem(at: fileURL) } - do { - let metadata = try await ref.putFileAsync(from: fileURL) - XCTAssertEqual(metadata.size, Int64(data.count)) - } catch { - XCTFail("Unexpected failure: \(error)") - } + let metadata = try await ref.putFileAsync(from: fileURL) + XCTAssertEqual(metadata.size, Int64(data.count)) } } diff --git a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift new file mode 100644 index 00000000000..a568730f758 --- /dev/null +++ b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift @@ -0,0 +1,57 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@testable import FirebaseStorage +import Foundation +#if COCOAPODS + import GTMSessionFetcher +#else + import GTMSessionFetcherCore +#endif +import XCTest + +class StoragePutFileTests: StorageTestHelpers { + func testPutFileWithPOSIXError40UpdatesExistingFetcherService() async throws { + // Initialize storage *before* setting the testBlock to verify that + // `StorageFetcherService.updateTestBlock` correctly updates pre-existing instances. + let storageInstance = storage() + let ref = storageInstance.reference(withPath: "ios/public/testPOSIX40") + + let testBlock: GTMSessionFetcherTestBlock = { (fetcher, response) in + let error = NSError(domain: NSPOSIXErrorDomain, code: 40, userInfo: nil) + response(nil, nil, error) + } + + await StorageFetcherService.shared.updateTestBlock(testBlock) + + let data = try XCTUnwrap("Hello".data(using: .utf8)) + let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) + let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") + try data.write(to: fileURL, options: .atomicWrite) + + do { + _ = try await ref.putFileAsync(from: fileURL) + XCTFail("Unexpected success") + } catch let error as NSError { + XCTAssertEqual(error.domain, StorageErrorDomain) + XCTAssertEqual(error.code, StorageErrorCode.unknown.rawValue) + let message = error.localizedDescription + XCTAssertTrue(message.contains("POSIX errno 40 (Message too long)"), + "Error message should contain 'POSIX errno 40 (Message too long)', but got \(message)") + } + + try? FileManager.default.removeItem(at: fileURL) + await StorageFetcherService.shared.updateTestBlock(nil) + } +} diff --git a/FirebaseStorage/Tests/Unit/StorageTests.swift b/FirebaseStorage/Tests/Unit/StorageTests.swift index bbc19194c62..cc9926c8b7a 100644 --- a/FirebaseStorage/Tests/Unit/StorageTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageTests.swift @@ -256,6 +256,17 @@ class StorageTests: XCTestCase { XCTAssertEqual(storage.maxOperationRetryInterval, 8) } + func testPOSIXErrorFormatting() throws { + let app = try getApp(bucket: "bucket") + let storage = Storage.storage(app: app) + let ref = storage.reference(withPath: "ios/public/testPOSIX40") + let posixError = NSError(domain: NSPOSIXErrorDomain, code: 40, userInfo: nil) + let storageError = StorageErrorCode.error(withServerError: posixError, ref: ref) + XCTAssertEqual(storageError.domain, StorageErrorDomain) + XCTAssertEqual(storageError.code, StorageErrorCode.unknown.rawValue) + XCTAssertEqual(storageError.userInfo[NSLocalizedDescriptionKey] as? String, "POSIX errno 40 (Message too long)") + } + // MARK: Private Helpers // Cache the app associated with each Storage bucket From c23583396090abc0823feb170ab90eda7c1d364c Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 17:43:40 -0700 Subject: [PATCH 07/12] review --- .../Sources/StorageUploadTask.swift | 9 ++++----- .../Tests/Unit/StoragePutFileTests.swift | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/FirebaseStorage/Sources/StorageUploadTask.swift b/FirebaseStorage/Sources/StorageUploadTask.swift index 280f69d79e1..49849ed6312 100644 --- a/FirebaseStorage/Sources/StorageUploadTask.swift +++ b/FirebaseStorage/Sources/StorageUploadTask.swift @@ -113,13 +113,12 @@ import Foundation uploadFetcher.comment = "File UploadTask" #if targetEnvironment(simulator) - let supportsBackground = false + uploadFetcher.useBackgroundSession = false #else - let supportsBackground = GULAppEnvironmentUtil.supportsBackgroundURLSessionUploads() + if !GULAppEnvironmentUtil.supportsBackgroundURLSessionUploads() { + uploadFetcher.useBackgroundSession = false + } #endif - if !supportsBackground { - uploadFetcher.useBackgroundSession = false - } } uploadFetcher.maxRetryInterval = self.reference.storage.maxUploadRetryInterval diff --git a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift index a568730f758..63a82effa73 100644 --- a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift +++ b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift @@ -27,19 +27,26 @@ class StoragePutFileTests: StorageTestHelpers { // `StorageFetcherService.updateTestBlock` correctly updates pre-existing instances. let storageInstance = storage() let ref = storageInstance.reference(withPath: "ios/public/testPOSIX40") - - let testBlock: GTMSessionFetcherTestBlock = { (fetcher, response) in + + let testBlock: GTMSessionFetcherTestBlock = { fetcher, response in let error = NSError(domain: NSPOSIXErrorDomain, code: 40, userInfo: nil) response(nil, nil, error) } - await StorageFetcherService.shared.updateTestBlock(testBlock) - + addTeardownBlock { + await StorageFetcherService.shared.updateTestBlock(nil) + } + + await StorageFetcherService.shared.updateTestBlock(testBlock) + let data = try XCTUnwrap("Hello".data(using: .utf8)) let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") try data.write(to: fileURL, options: .atomicWrite) - + defer { + try? FileManager.default.removeItem(at: fileURL) + } + do { _ = try await ref.putFileAsync(from: fileURL) XCTFail("Unexpected success") @@ -50,7 +57,7 @@ class StoragePutFileTests: StorageTestHelpers { XCTAssertTrue(message.contains("POSIX errno 40 (Message too long)"), "Error message should contain 'POSIX errno 40 (Message too long)', but got \(message)") } - + try? FileManager.default.removeItem(at: fileURL) await StorageFetcherService.shared.updateTestBlock(nil) } From 7045ff37cdd1c7d71ecfff5798eb17afc1040fbb Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 17:49:40 -0700 Subject: [PATCH 08/12] more review --- FirebaseStorage/Sources/StorageError.swift | 5 ++++- FirebaseStorage/Tests/Unit/StoragePutFileTests.swift | 5 ----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/FirebaseStorage/Sources/StorageError.swift b/FirebaseStorage/Sources/StorageError.swift index fd4693b1668..fec74edb3f8 100644 --- a/FirebaseStorage/Sources/StorageError.swift +++ b/FirebaseStorage/Sources/StorageError.swift @@ -79,8 +79,11 @@ public let StorageErrorDomain: String = "FIRStorageErrorDomain" ) default: if serverError.domain == NSPOSIXErrorDomain { + let errorCode = Int32(truncatingIfNeeded: serverError.code) + var buffer = [CChar](repeating: 0, count: 128) + _ = strerror_r(errorCode, &buffer, buffer.count) StorageError.unknown( - message: "POSIX errno \(serverError.code) (\(String(cString: strerror(Int32(truncatingIfNeeded: serverError.code)))))", + message: "POSIX errno \(serverError.code) (\(String(cString: buffer)))", serverError: errorDictionary ) } else { diff --git a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift index 63a82effa73..2ed3efdcda1 100644 --- a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift +++ b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift @@ -37,8 +37,6 @@ class StoragePutFileTests: StorageTestHelpers { await StorageFetcherService.shared.updateTestBlock(nil) } - await StorageFetcherService.shared.updateTestBlock(testBlock) - let data = try XCTUnwrap("Hello".data(using: .utf8)) let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") @@ -57,8 +55,5 @@ class StoragePutFileTests: StorageTestHelpers { XCTAssertTrue(message.contains("POSIX errno 40 (Message too long)"), "Error message should contain 'POSIX errno 40 (Message too long)', but got \(message)") } - - try? FileManager.default.removeItem(at: fileURL) - await StorageFetcherService.shared.updateTestBlock(nil) } } From 6a0f6aac444c944bc14d33b8d5ae23ed4c8544cb Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 10 Jul 2026 18:22:48 -0700 Subject: [PATCH 09/12] review --- .../Internal/StorageFetcherService.swift | 4 +-- FirebaseStorage/Sources/StorageError.swift | 29 ++++++++++--------- FirebaseStorage/Tests/Unit/StorageTests.swift | 5 +++- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/FirebaseStorage/Sources/Internal/StorageFetcherService.swift b/FirebaseStorage/Sources/Internal/StorageFetcherService.swift index 6ec9d8f3029..be19032f0f2 100644 --- a/FirebaseStorage/Sources/Internal/StorageFetcherService.swift +++ b/FirebaseStorage/Sources/Internal/StorageFetcherService.swift @@ -63,8 +63,8 @@ actor StorageFetcherService { if let _fetcherService { _fetcherService.testBlock = testBlock } - for (_, bucketMap) in fetcherServiceMap { - for (_, fetcherService) in bucketMap { + for bucketMap in fetcherServiceMap.values { + for fetcherService in bucketMap.values { fetcherService.testBlock = testBlock } } diff --git a/FirebaseStorage/Sources/StorageError.swift b/FirebaseStorage/Sources/StorageError.swift index fec74edb3f8..b442e67cb23 100644 --- a/FirebaseStorage/Sources/StorageError.swift +++ b/FirebaseStorage/Sources/StorageError.swift @@ -78,19 +78,22 @@ public let StorageErrorDomain: String = "FIRStorageErrorDomain" object: ref.path.object ?? "", serverError: errorDictionary ) default: - if serverError.domain == NSPOSIXErrorDomain { - let errorCode = Int32(truncatingIfNeeded: serverError.code) - var buffer = [CChar](repeating: 0, count: 128) - _ = strerror_r(errorCode, &buffer, buffer.count) - StorageError.unknown( - message: "POSIX errno \(serverError.code) (\(String(cString: buffer)))", - serverError: errorDictionary - ) - } else { - StorageError.unknown( - message: "Unexpected \(serverError.code) code from backend", serverError: errorDictionary - ) - } + { () -> StorageError in + if serverError.domain == NSPOSIXErrorDomain { + let errorCode = Int32(truncatingIfNeeded: serverError.code) + var buffer = [CChar](repeating: 0, count: 128) + _ = strerror_r(errorCode, &buffer, buffer.count) + return StorageError.unknown( + message: "POSIX errno \(serverError.code) (\(String(cString: buffer)))", + serverError: errorDictionary + ) + } else { + return StorageError.unknown( + message: "Unexpected \(serverError.code) code from backend", + serverError: errorDictionary + ) + } + }() } return storageError as NSError } diff --git a/FirebaseStorage/Tests/Unit/StorageTests.swift b/FirebaseStorage/Tests/Unit/StorageTests.swift index cc9926c8b7a..b7c280ff39d 100644 --- a/FirebaseStorage/Tests/Unit/StorageTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageTests.swift @@ -264,7 +264,10 @@ class StorageTests: XCTestCase { let storageError = StorageErrorCode.error(withServerError: posixError, ref: ref) XCTAssertEqual(storageError.domain, StorageErrorDomain) XCTAssertEqual(storageError.code, StorageErrorCode.unknown.rawValue) - XCTAssertEqual(storageError.userInfo[NSLocalizedDescriptionKey] as? String, "POSIX errno 40 (Message too long)") + XCTAssertEqual( + storageError.userInfo[NSLocalizedDescriptionKey] as? String, + "POSIX errno 40 (Message too long)" + ) } // MARK: Private Helpers From a4bae12ef1a98f638da90725c5d0dfdea5c268ef Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 13 Jul 2026 07:42:18 -0700 Subject: [PATCH 10/12] review --- FirebaseStorage/Sources/StorageError.swift | 25 +++++++------------ .../Integration/StoragePOSIXErrorTest.swift | 2 +- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/FirebaseStorage/Sources/StorageError.swift b/FirebaseStorage/Sources/StorageError.swift index b442e67cb23..662be235c73 100644 --- a/FirebaseStorage/Sources/StorageError.swift +++ b/FirebaseStorage/Sources/StorageError.swift @@ -77,23 +77,16 @@ public let StorageErrorDomain: String = "FIRStorageErrorDomain" case 404: StorageError.objectNotFound( object: ref.path.object ?? "", serverError: errorDictionary ) + case _ where serverError.domain == NSPOSIXErrorDomain: + StorageError.unknown( + message: "POSIX errno \(serverError.code) (\(serverError.localizedDescription))", + serverError: errorDictionary + ) default: - { () -> StorageError in - if serverError.domain == NSPOSIXErrorDomain { - let errorCode = Int32(truncatingIfNeeded: serverError.code) - var buffer = [CChar](repeating: 0, count: 128) - _ = strerror_r(errorCode, &buffer, buffer.count) - return StorageError.unknown( - message: "POSIX errno \(serverError.code) (\(String(cString: buffer)))", - serverError: errorDictionary - ) - } else { - return StorageError.unknown( - message: "Unexpected \(serverError.code) code from backend", - serverError: errorDictionary - ) - } - }() + StorageError.unknown( + message: "Unexpected \(serverError.code) code from backend", + serverError: errorDictionary + ) } return storageError as NSError } diff --git a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift index 9feb47e514d..96b85df4dfd 100644 --- a/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift +++ b/FirebaseStorage/Tests/Integration/StoragePOSIXErrorTest.swift @@ -30,7 +30,7 @@ class StoragePOSIXErrorTest: StorageIntegrationCommon { let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") try data.write(to: fileURL, options: .atomicWrite) - defer { + addTeardownBlock { try? FileManager.default.removeItem(at: fileURL) } From e0932134937e16c82f86f9d8afab13f8d3a3df76 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 13 Jul 2026 11:05:22 -0700 Subject: [PATCH 11/12] Test updates for previous library change --- FirebaseStorage/Tests/Unit/StoragePutFileTests.swift | 6 +++--- FirebaseStorage/Tests/Unit/StorageTests.swift | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift index 2ed3efdcda1..fd2a2bfcbab 100644 --- a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift +++ b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift @@ -41,7 +41,7 @@ class StoragePutFileTests: StorageTestHelpers { let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory()) let fileURL = tmpDirURL.appendingPathComponent(#function + "hello.txt") try data.write(to: fileURL, options: .atomicWrite) - defer { + addTeardownBlock { try? FileManager.default.removeItem(at: fileURL) } @@ -52,8 +52,8 @@ class StoragePutFileTests: StorageTestHelpers { XCTAssertEqual(error.domain, StorageErrorDomain) XCTAssertEqual(error.code, StorageErrorCode.unknown.rawValue) let message = error.localizedDescription - XCTAssertTrue(message.contains("POSIX errno 40 (Message too long)"), - "Error message should contain 'POSIX errno 40 (Message too long)', but got \(message)") + XCTAssertTrue(message.contains("POSIX errno 40 (The operation couldn’t be completed. Message too long)"), + "Error message should contain 'POSIX errno 40 (The operation couldn’t be completed. Message too long)', but got \(message)") } } } diff --git a/FirebaseStorage/Tests/Unit/StorageTests.swift b/FirebaseStorage/Tests/Unit/StorageTests.swift index b7c280ff39d..50bda77e224 100644 --- a/FirebaseStorage/Tests/Unit/StorageTests.swift +++ b/FirebaseStorage/Tests/Unit/StorageTests.swift @@ -266,7 +266,7 @@ class StorageTests: XCTestCase { XCTAssertEqual(storageError.code, StorageErrorCode.unknown.rawValue) XCTAssertEqual( storageError.userInfo[NSLocalizedDescriptionKey] as? String, - "POSIX errno 40 (Message too long)" + "POSIX errno 40 (The operation couldn’t be completed. Message too long)" ) } From 7d3a867578de06cb2c345bcdb67021623f260eb8 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Mon, 13 Jul 2026 11:24:04 -0700 Subject: [PATCH 12/12] style --- FirebaseStorage/Tests/Unit/StoragePutFileTests.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift index fd2a2bfcbab..b524cce8e42 100644 --- a/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift +++ b/FirebaseStorage/Tests/Unit/StoragePutFileTests.swift @@ -52,8 +52,10 @@ class StoragePutFileTests: StorageTestHelpers { XCTAssertEqual(error.domain, StorageErrorDomain) XCTAssertEqual(error.code, StorageErrorCode.unknown.rawValue) let message = error.localizedDescription - XCTAssertTrue(message.contains("POSIX errno 40 (The operation couldn’t be completed. Message too long)"), - "Error message should contain 'POSIX errno 40 (The operation couldn’t be completed. Message too long)', but got \(message)") + XCTAssertTrue( + message.contains("POSIX errno 40 (The operation couldn’t be completed. Message too long)"), + "Error message should contain 'POSIX errno 40 (The operation couldn’t be completed. Message too long)', but got \(message)" + ) } } }