@@ -237,6 +237,17 @@ public void addCompletionListener(Consumer<AsyncSearchResponse> listener) {
237237 : ExceptionsHelper .convertToElastic (e );
238238 ex .setStackTrace (new StackTraceElement [0 ]);
239239
240+ // We are in the failure path where no MutableSearchResponse can be produced or retained.
241+ // This happens only after the in-memory reference has been released and the stored response
242+ // cannot be retrieved or retained (tryIncRef() failed or the doc is unavailable). At this point
243+ // it is unsafe to call searchResponse.toAsyncSearchResponse(...): the underlying
244+ // MutableSearchResponse is ref-counted and may already be closed (refcount == 0).
245+ //
246+ // Instead, we synthesize a minimal AsyncSearchResponse that carries the exception back to
247+ // the caller. We set isRunning=false because both the in-memory state and stored document
248+ // are unavailable and no further work can be observed. For isPartial we use false as a
249+ // conservative choice: partial results may have existed earlier, but they are no longer
250+ // accessible and we must not imply that any partial data is included.
240251 AsyncSearchResponse failureResponse = new AsyncSearchResponse (
241252 searchId .getEncoded (),
242253 null ,
@@ -348,6 +359,17 @@ private void executeCompletionListeners() {
348359 : ExceptionsHelper .convertToElastic (e );
349360 ex .setStackTrace (new StackTraceElement [0 ]);
350361
362+ // We are in the failure path where no MutableSearchResponse can be produced or retained.
363+ // This happens only after the in-memory reference has been released and the stored response
364+ // cannot be retrieved or retained (tryIncRef() failed or the doc is unavailable). At this point
365+ // it is unsafe to call searchResponse.toAsyncSearchResponse(...): the underlying
366+ // MutableSearchResponse is ref-counted and may already be closed (refcount == 0).
367+ //
368+ // Instead, we synthesize a minimal AsyncSearchResponse that carries the exception back to
369+ // the caller. We set isRunning=false because both the in-memory state and stored document
370+ // are unavailable and no further work can be observed. For isPartial we use false as a
371+ // conservative choice: partial results may have existed earlier, but they are no longer
372+ // accessible and we must not imply that any partial data is included.
351373 AsyncSearchResponse failureResponse = new AsyncSearchResponse (
352374 searchId .getEncoded (),
353375 null ,
0 commit comments