From 47c5e45df01a07f86c72a1f71368dcad16646e1a Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 1 Sep 2026 13:04:52 -0600 Subject: [PATCH 1/2] Guard against nil reply in createReplyForComment callback createReplyForComment's completion is annotated non-null but its implementation can pass nil: it re-resolves the reply on the main context via existingObjectWithID:error:, which returns nil when the optimistic comment can't be resolved again (a rare Core Data race). Annotate the callback _Nullable so it imports into Swift as Comment?, and guard the single caller so a nil reply resumes with a failure instead of forwarding nil into uploadComment. Adding the guard makes that completion a multi-statement closure, so pin the continuation type explicitly (UnsafeContinuation) to keep T inferable. --- WordPress/Classes/Services/CommentService.h | 2 +- WordPress/Classes/Services/CommentService.m | 2 +- .../Comments/Controllers/CommentDetailViewController.swift | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/Services/CommentService.h b/WordPress/Classes/Services/CommentService.h index ff84f9ce9717..970b7eb5ef95 100644 --- a/WordPress/Classes/Services/CommentService.h +++ b/WordPress/Classes/Services/CommentService.h @@ -32,7 +32,7 @@ extern NSUInteger const WPTopLevelHierarchicalCommentsPerPage; - (instancetype)init NS_UNAVAILABLE; // Create reply -- (void)createReplyForComment:(Comment *)comment content:(NSString *)content completion:(void (^)(Comment *reply))completion; +- (void)createReplyForComment:(Comment *)comment content:(NSString *)content completion:(void (^)(Comment * _Nullable reply))completion; // Sync comments - (void)syncCommentsForBlog:(Blog *)blog diff --git a/WordPress/Classes/Services/CommentService.m b/WordPress/Classes/Services/CommentService.m index dca4f0f8e765..8adde1b3822c 100644 --- a/WordPress/Classes/Services/CommentService.m +++ b/WordPress/Classes/Services/CommentService.m @@ -100,7 +100,7 @@ - (Comment *)createCommentForBlog:(Blog *)blog } // Create reply -- (void)createReplyForComment:(Comment *)comment content:(NSString *)content completion:(void (^)(Comment *reply))completion +- (void)createReplyForComment:(Comment *)comment content:(NSString *)content completion:(void (^)(Comment * _Nullable reply))completion { NSManagedObjectID *parentCommentID = comment.objectID; NSManagedObjectID * __block replyID = nil; diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift index e6b0e0eef0bc..297438d5fd86 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift @@ -1011,8 +1011,12 @@ private extension CommentDetailViewController { return } - try await withUnsafeThrowingContinuation { continuation in + try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation) in commentService.createReply(for: comment, content: content) { reply in + guard let reply else { + continuation.resume(throwing: URLError(.unknown)) + return + } self.commentService.uploadComment(reply, success: { [weak self] in self?.refreshCommentReplyIfNeeded() continuation.resume() From e5d23974b644ab4700c977ee67b99949df6eccee Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 1 Sep 2026 13:23:09 -0600 Subject: [PATCH 2/2] Log the nil reply case in createReply The two sibling failure paths in createReply already DDLogError; the nil-reply guard was the one silent path, leaving a rare local Core Data materialization failure indistinguishable from a network error in the logs. --- .../Comments/Controllers/CommentDetailViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift index 297438d5fd86..4babcbad0484 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/CommentDetailViewController.swift @@ -1014,6 +1014,7 @@ private extension CommentDetailViewController { try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation) in commentService.createReply(for: comment, content: content) { reply in guard let reply else { + DDLogError("Failed creating comment reply: reply was nil after save") continuation.resume(throwing: URLError(.unknown)) return }