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

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


The following commit(s) were added to refs/heads/master by this push:
     new b82ff27f9cc fix(sqllab): render each query error once on async 
fallback (#42318)
b82ff27f9cc is described below

commit b82ff27f9cc18f559ca9eed478ba1cdb0a93de7c
Author: Joe Li <[email protected]>
AuthorDate: Fri Jul 24 14:13:35 2026 -0700

    fix(sqllab): render each query error once on async fallback (#42318)
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
    Co-authored-by: Evan Rusackas <[email protected]>
---
 .../SqlLab/components/ResultSet/ResultSet.test.tsx | 29 ++++++++++++++++++++++
 .../src/SqlLab/components/ResultSet/index.tsx      | 21 +++++++++++++++-
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git 
a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx 
b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
index 99388fa7ca3..63a239ddcd5 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
@@ -355,6 +355,35 @@ describe('ResultSet', () => {
     expect(errorMessages).toHaveLength(errors.length);
   });
 
+  test('deduplicates errors present in both query.errors and 
query.extra.errors', async () => {
+    // The async fallback path (QueryAutoRefresh) populates both
+    // `query.errors` (via queryFailed) and `query.extra.errors` (via
+    // refreshQueries) with the same errors. ResultSet should render each
+    // error only once, not twice.
+    const duplicatedErrorQuery = {
+      ...failedQueryWithErrors,
+      extra: { errors: failedQueryWithErrors.errors },
+    };
+    const duplicatedErrorState = {
+      ...initialState,
+      sqlLab: {
+        ...initialState.sqlLab,
+        queries: {
+          [duplicatedErrorQuery.id]: duplicatedErrorQuery,
+        },
+      },
+    };
+
+    await waitFor(() => {
+      setup(
+        { ...mockedProps, queryId: duplicatedErrorQuery.id },
+        mockStore(duplicatedErrorState),
+      );
+    });
+    const errorMessages = screen.getAllByTestId('error-message');
+    expect(errorMessages).toHaveLength(failedQueryWithErrors.errors.length);
+  });
+
   test('should render a timeout error with a retrial button', async () => {
     await waitFor(() => {
       setup(
diff --git a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx 
b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
index 7fc71d13534..a4c24a34c80 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
@@ -618,7 +618,26 @@ const ResultSet = ({
   }
 
   if (query.state === QueryState.Failed) {
-    const errors = [...(query.extra?.errors || []), ...(query.errors || [])];
+    // A failed query can carry the same error in both `query.errors` (set by
+    // the queryFailed action) and `query.extra.errors` (set by the async
+    // refresh). When falling back to async polling both get populated with
+    // identical errors, so deduplicate to avoid rendering each error twice.
+    const seenErrors = new Set<string>();
+    const errors = [
+      ...(query.extra?.errors || []),
+      ...(query.errors || []),
+    ].filter(error => {
+      // json-bigint parsing can leave native BigInt values in payloads,
+      // which JSON.stringify rejects; serialize them as strings.
+      const key = JSON.stringify(error, (_, value) =>
+        typeof value === 'bigint' ? value.toString() : value,
+      );
+      if (seenErrors.has(key)) {
+        return false;
+      }
+      seenErrors.add(key);
+      return true;
+    });
 
     return (
       <ResultlessStyles>

Reply via email to