From 09cc3ccd68ae1346dce2cbd00e69d3f5cc5fcf4d Mon Sep 17 00:00:00 2001 From: George Birch Date: Wed, 7 Jan 2026 10:17:47 -0800 Subject: [PATCH 1/6] throw download manager error for non-2xx http status, log http status --- .../Source/Helpers/DownloadManager.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift index 4ffa9b4a631e..167f2ae726b3 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift @@ -16,6 +16,7 @@ import UIKit enum Error: Swift.Error { case failedToMakeImageFromData + case httpError } public static let sharedManager = DownloadManager() @@ -93,8 +94,16 @@ extension DownloadManager { // Common download functions private func downloadImageSkippingCacheRead(url: URL) async throws -> UIImage { + var errorParams: [String: Any] = ["url": url.absoluteString] do { - let (data, _) = try await session.data(from: url) + let (data, response) = try await session.data(from: url) + guard let httpResponse = response as? HTTPURLResponse else { + throw DownloadManager.Error.httpError + } + errorParams["httpStatus"] = httpResponse.statusCode + guard (200...299).contains(httpResponse.statusCode) else { + throw DownloadManager.Error.httpError + } let image = try UIImage.from(imageData: data) // Throws a Error.failedToMakeImageFromData Task { // Cache the image in memory @@ -107,7 +116,7 @@ extension DownloadManager { } catch { let errorAnalytic = ErrorAnalytic(event: .stripePaymentSheetDownloadManagerError, error: error, - additionalNonPIIParams: ["url": url.absoluteString]) + additionalNonPIIParams: errorParams) analyticsClient.log(analytic: errorAnalytic) throw error } From 156d40b26cb5b3e3a863f9393d44ffd4c879da2f Mon Sep 17 00:00:00 2001 From: George Birch Date: Fri, 9 Jan 2026 11:36:55 -0800 Subject: [PATCH 2/6] change error param from camel case to snake case to match convention --- .../StripePaymentSheet/Source/Helpers/DownloadManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift index 167f2ae726b3..7c3ca72e584f 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift @@ -100,7 +100,7 @@ extension DownloadManager { guard let httpResponse = response as? HTTPURLResponse else { throw DownloadManager.Error.httpError } - errorParams["httpStatus"] = httpResponse.statusCode + errorParams["http_status"] = httpResponse.statusCode guard (200...299).contains(httpResponse.statusCode) else { throw DownloadManager.Error.httpError } From f4327b0fc22d8eeeb978f141588347acbdb6aa94 Mon Sep 17 00:00:00 2001 From: George Birch Date: Fri, 9 Jan 2026 11:37:55 -0800 Subject: [PATCH 3/6] add explanation comment --- .../StripePaymentSheet/Source/Helpers/DownloadManager.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift index 7c3ca72e584f..ca2b9c3cae6d 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift @@ -97,6 +97,7 @@ extension DownloadManager { var errorParams: [String: Any] = ["url": url.absoluteString] do { let (data, response) = try await session.data(from: url) + // this should never fail, but need to cast to extract http status guard let httpResponse = response as? HTTPURLResponse else { throw DownloadManager.Error.httpError } From 156587daf0df4a103219aa831c54ee3ca3984a9a Mon Sep 17 00:00:00 2001 From: George Birch Date: Fri, 9 Jan 2026 11:43:09 -0800 Subject: [PATCH 4/6] leave logic in place, only log extra status --- .../Source/Helpers/DownloadManager.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift index ca2b9c3cae6d..00173948a5a8 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift @@ -97,13 +97,8 @@ extension DownloadManager { var errorParams: [String: Any] = ["url": url.absoluteString] do { let (data, response) = try await session.data(from: url) - // this should never fail, but need to cast to extract http status - guard let httpResponse = response as? HTTPURLResponse else { - throw DownloadManager.Error.httpError - } - errorParams["http_status"] = httpResponse.statusCode - guard (200...299).contains(httpResponse.statusCode) else { - throw DownloadManager.Error.httpError + if let httpResponse = response as? HTTPURLResponse { + errorParams["http_status"] = httpResponse.statusCode } let image = try UIImage.from(imageData: data) // Throws a Error.failedToMakeImageFromData Task { @@ -111,7 +106,6 @@ extension DownloadManager { self.imageCacheLock.withLock { self.imageCache[url] = image } - } return image } catch { From ee87b09849095773ed61c5944dca07e63b1467ec Mon Sep 17 00:00:00 2001 From: George Birch Date: Fri, 9 Jan 2026 11:43:55 -0800 Subject: [PATCH 5/6] remove httperror type --- .../StripePaymentSheet/Source/Helpers/DownloadManager.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift index 00173948a5a8..bc9ec1330567 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift @@ -16,7 +16,6 @@ import UIKit enum Error: Swift.Error { case failedToMakeImageFromData - case httpError } public static let sharedManager = DownloadManager() From 6f0e260d64cef443f7cbee96564749a5f2cef93d Mon Sep 17 00:00:00 2001 From: George Birch Date: Fri, 9 Jan 2026 11:58:22 -0800 Subject: [PATCH 6/6] log extra error analytic info --- .../StripePaymentSheet/Source/Helpers/DownloadManager.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift index bc9ec1330567..0268934a1f03 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Helpers/DownloadManager.swift @@ -96,8 +96,11 @@ extension DownloadManager { var errorParams: [String: Any] = ["url": url.absoluteString] do { let (data, response) = try await session.data(from: url) + // log extra info about response for analytics in case of error if let httpResponse = response as? HTTPURLResponse { errorParams["http_status"] = httpResponse.statusCode + errorParams["content_type"] = httpResponse.allHeaderFields["Content-Type"] + errorParams["content_length"] = httpResponse.allHeaderFields["Content-Length"] } let image = try UIImage.from(imageData: data) // Throws a Error.failedToMakeImageFromData Task {