This is an automated email from the ASF dual-hosted git repository.

JNSimba pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new deb079478d0 [fix](fe) Report missing backend during stream load 
planning (#69989)
deb079478d0 is described below

commit deb079478d0114d79b04166b22861918fcdd7a51
Author: wudi <[email protected]>
AuthorDate: Tue Nov 3 14:23:43 2026 +0800

    [fix](fe) Report missing backend during stream load planning (#69989)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Problem Summary:
    
    A cloud Stream Load request can still arrive from a BE after scaling has
    removed that BE from FE metadata. Resolving the compute group then
    obtains a null backend and throws a NullPointerException, which reaches
    the caller as a generic INTERNAL_ERROR.
    
    Return a descriptive UserException containing the missing backend ID
    instead. The existing RPC exception handler converts it to
    ANALYSIS_ERROR. The request fails before plan generation, allowing the
    existing CDC task failure and automatic rescheduling flow to handle
    recovery.
    
    Add an RPC-level test for a missing backend with token authentication
    and a compute-group header. It checks the returned status and backend
    ID, absence of an execution plan, and ConnectContext cleanup.
---
 .../org/apache/doris/load/StreamLoadHandler.java   |  4 ++-
 .../apache/doris/load/StreamLoadHandlerTest.java   | 33 ++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java 
b/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java
index 06fde6758dc..84acd0f2b87 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java
@@ -146,7 +146,9 @@ public class StreamLoadHandler {
         if (request.isSetBackendId()) {
             long backendId = request.getBackendId();
             Backend backend = Env.getCurrentSystemInfo().getBackend(backendId);
-            Preconditions.checkNotNull(backend);
+            if (backend == null) {
+                throw new UserException("Backend " + backendId + " does not 
exist");
+            }
             String computeGroup = backend.getCloudClusterName();
             // Token/auth-code and user-less internal loads keep their 
existing trusted path. Regular
             // stream loads must still validate compute group privilege, 
existence, and status.
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/load/StreamLoadHandlerTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/load/StreamLoadHandlerTest.java
index 6ec4ea387c0..00e4a149b84 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/load/StreamLoadHandlerTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/load/StreamLoadHandlerTest.java
@@ -35,6 +35,7 @@ import org.apache.doris.mysql.privilege.Auth;
 import org.apache.doris.nereids.load.NereidsStreamLoadPlanner;
 import org.apache.doris.nereids.load.NereidsStreamLoadTask;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.service.FrontendServiceImpl;
 import org.apache.doris.system.Backend;
 import org.apache.doris.system.SystemInfoService;
 import org.apache.doris.thrift.TDataSink;
@@ -47,6 +48,7 @@ import org.apache.doris.thrift.TOlapTableSink;
 import org.apache.doris.thrift.TPipelineFragmentParams;
 import org.apache.doris.thrift.TPlanFragment;
 import org.apache.doris.thrift.TQueryOptions;
+import org.apache.doris.thrift.TStatusCode;
 import org.apache.doris.thrift.TStreamLoadPutRequest;
 import org.apache.doris.thrift.TStreamLoadPutResult;
 import org.apache.doris.thrift.TTabletLocation;
@@ -59,6 +61,7 @@ import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
@@ -272,6 +275,36 @@ public class StreamLoadHandlerTest {
         }
     }
 
+    @Test
+    public void testStreamLoadPutRejectsMissingBackend() throws Exception {
+        SystemInfoService originalSystemInfoService = 
Env.getCurrentSystemInfo();
+        String originalCloudUniqueId = Config.cloud_unique_id;
+        CloudSystemInfoService systemInfoService =
+                new TestCloudSystemInfoService(Collections.emptyList());
+        TStreamLoadPutRequest request = new TStreamLoadPutRequest();
+        request.setUser("");
+        request.setToken("test_token");
+        request.setBackendId(10001L);
+        request.setCloudCluster("header_compute_group");
+
+        try {
+            Config.cloud_unique_id = "test_cloud_unique_id";
+            Deencapsulation.setField(Env.getCurrentEnv(), "systemInfo", 
systemInfoService);
+            ConnectContext.remove();
+
+            TStreamLoadPutResult result = new 
FrontendServiceImpl(null).streamLoadPut(request);
+
+            Assertions.assertEquals(TStatusCode.ANALYSIS_ERROR, 
result.getStatus().getStatusCode());
+            
Assertions.assertTrue(result.getStatus().getErrorMsgs().get(0).contains("10001"));
+            Assertions.assertFalse(result.isSetPipelineParams());
+            Assertions.assertNull(ConnectContext.get());
+        } finally {
+            ConnectContext.remove();
+            Config.cloud_unique_id = originalCloudUniqueId;
+            Deencapsulation.setField(Env.getCurrentEnv(), "systemInfo", 
originalSystemInfoService);
+        }
+    }
+
     @Test
     public void testGroupCommitValidatesBackendComputeGroupPrivilege() throws 
Exception {
         String originalCloudUniqueId = Config.cloud_unique_id;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to