From 7fc9eac6c923232317cf484995e075e69b6cf0ac Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Sat, 1 Aug 2026 23:24:58 +0800 Subject: [PATCH] fix: prevent NPE in RetriableStream when cancel() races start() (#12964) --- .../io/grpc/internal/RetriableStream.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/core/src/main/java/io/grpc/internal/RetriableStream.java b/core/src/main/java/io/grpc/internal/RetriableStream.java index 0c37a0beaca..4ddd24b3e93 100644 --- a/core/src/main/java/io/grpc/internal/RetriableStream.java +++ b/core/src/main/java/io/grpc/internal/RetriableStream.java @@ -392,6 +392,26 @@ public void runWith(Substream substream) { public final void start(ClientStreamListener listener) { masterListener = listener; + if (savedCloseMasterListenerReason != null) { + // cancel() was called before start() completed; close immediately with + // the already-saved reason. + listenerSerializeExecutor.execute( + new Runnable() { + @Override + public void run() { + if (masterListener == null || isClosed) { + return; + } + isClosed = true; + masterListener.closed( + savedCloseMasterListenerReason.status, + savedCloseMasterListenerReason.progress, + savedCloseMasterListenerReason.metadata); + } + }); + return; + } + Status shutdownStatus = prestart(); if (shutdownStatus != null) { @@ -844,6 +864,9 @@ private void safeCloseMasterListener(Status status, RpcProgress progress, Metada new Runnable() { @Override public void run() { + if (masterListener == null) { + return; + } isClosed = true; masterListener.closed(status, progress, metadata); }