diff --git a/superset-frontend/src/components/Chart/chartAction.js b/superset-frontend/src/components/Chart/chartAction.js index bd9bd94a56ba..d8ad30d79396 100644 --- a/superset-frontend/src/components/Chart/chartAction.js +++ b/superset-frontend/src/components/Chart/chartAction.js @@ -476,7 +476,16 @@ export function exploreJSON( return dispatch(chartUpdateSucceeded(queriesResponse, key)); }) .catch(response => { + // Ignore abort errors - they're expected when filters change quickly + const isAbort = + response?.name === 'AbortError' || response?.statusText === 'abort'; + if (isAbort) { + // Abort is expected: filters changed, chart unmounted, etc. + return dispatch(chartUpdateStopped(key)); + } + if (isFeatureEnabled(FeatureFlag.GlobalAsyncQueries)) { + // In async mode we just pass the raw error response through return dispatch(chartUpdateFailed([response], key)); } @@ -494,10 +503,7 @@ export function exploreJSON( }), ); }; - if (response.name === 'AbortError') { - appendErrorLog('abort'); - return dispatch(chartUpdateStopped(key)); - } + return getClientErrorObject(response).then(parsedResponse => { if (response.statusText === 'timeout') { appendErrorLog('timeout'); diff --git a/superset-frontend/src/components/Chart/chartActions.test.js b/superset-frontend/src/components/Chart/chartActions.test.js index 4d57f53c2cb8..18c28de4ab01 100644 --- a/superset-frontend/src/components/Chart/chartActions.test.js +++ b/superset-frontend/src/components/Chart/chartActions.test.js @@ -357,6 +357,28 @@ describe('chart actions', () => { }); }); + test('should dispatch CHART_UPDATE_STOPPED action upon abort', () => { + fetchMock.post( + MOCK_URL, + { throws: { name: 'AbortError' } }, + { overwriteRoutes: true }, + ); + + const timeoutInSec = 100; + const actionThunk = actions.postChartFormData({}, false, timeoutInSec); + + return actionThunk(dispatch, mockGetState).then(() => { + const types = dispatch.args + .map(call => call[0] && call[0].type) + .filter(Boolean); + + expect(types).toContain(actions.CHART_UPDATE_STOPPED); + expect(types).not.toContain(actions.CHART_UPDATE_FAILED); + + setupDefaultFetchMock(); + }); + }); + test('should handle the bigint without regression', async () => { getExploreUrlStub.restore(); const mockBigIntUrl = '/mock/chart/data/bigint';