This is an automated email from the ASF dual-hosted git repository.
enzomartellucci 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 23b91d22ef fix(charts): properly parse error responses in
StatefulChart (#37130)
23b91d22ef is described below
commit 23b91d22efd68fa43a8f8dc3a80b917b329b2a65
Author: Enzo Martellucci <[email protected]>
AuthorDate: Thu Jan 15 15:22:45 2026 +0100
fix(charts): properly parse error responses in StatefulChart (#37130)
---
.../src/chart/components/StatefulChart.test.tsx | 92 ++++++++++++++++++++++
.../src/chart/components/StatefulChart.tsx | 11 ++-
2 files changed, 101 insertions(+), 2 deletions(-)
diff --git
a/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
b/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
index 35b65ac772..b02d3bb04a 100644
---
a/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
+++
b/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
@@ -471,3 +471,95 @@ test('should handle chartId changes', async () => {
expect(mockChartClient.loadFormData).toHaveBeenCalledTimes(2);
});
});
+
+test('should display error message when HTTP request fails with Response
object', async () => {
+ const errorBody = JSON.stringify({ message: 'Error: division by zero' });
+ const mockResponse = new Response(errorBody, {
+ status: 400,
+ statusText: 'Bad Request',
+ headers: { 'Content-Type': 'application/json' },
+ });
+ mockChartClient.client.post.mockRejectedValue(mockResponse);
+
+ const onError = jest.fn();
+ const { findByText } = render(
+ <StatefulChart
+ formData={mockFormData}
+ chartType="test_chart"
+ onError={onError}
+ />,
+ );
+
+ const errorElement = await findByText(/Error: division by zero/i);
+ expect(errorElement).toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(onError).toHaveBeenCalledTimes(1);
+ expect(onError).toHaveBeenCalledWith(expect.any(Error));
+ expect(onError.mock.calls[0][0].message).toBe('Error: division by zero');
+ });
+});
+
+test('should display error message when HTTP request fails with errors array',
async () => {
+ const errorBody = JSON.stringify({
+ errors: [
+ {
+ message: 'Query failed: column "invalid_col" does not exist',
+ error_type: 'COLUMN_DOES_NOT_EXIST_ERROR',
+ },
+ ],
+ });
+ const mockResponse = new Response(errorBody, {
+ status: 422,
+ statusText: 'Unprocessable Entity',
+ headers: { 'Content-Type': 'application/json' },
+ });
+ mockChartClient.client.post.mockRejectedValue(mockResponse);
+
+ const { findByText } = render(
+ <StatefulChart formData={mockFormData} chartType="test_chart" />,
+ );
+
+ const errorElement = await findByText(
+ /Query failed: column "invalid_col" does not exist/i,
+ );
+ expect(errorElement).toBeInTheDocument();
+});
+
+test('should display generic error message for network failures', async () => {
+ const networkError = new TypeError('Failed to fetch');
+ mockChartClient.client.post.mockRejectedValue(networkError);
+
+ const { findByText } = render(
+ <StatefulChart formData={mockFormData} chartType="test_chart" />,
+ );
+
+ const errorElement = await findByText(/Network error/i);
+ expect(errorElement).toBeInTheDocument();
+});
+
+test('should pass error to custom errorComponent when provided', async () => {
+ const errorBody = JSON.stringify({ message: 'Custom error message' });
+ const mockResponse = new Response(errorBody, {
+ status: 400,
+ statusText: 'Bad Request',
+ headers: { 'Content-Type': 'application/json' },
+ });
+ mockChartClient.client.post.mockRejectedValue(mockResponse);
+
+ const CustomErrorComponent = ({ error }: { error: Error }) => (
+ <div data-test="custom-error">Custom: {error.message}</div>
+ );
+
+ const { findByTestId } = render(
+ <StatefulChart
+ formData={mockFormData}
+ chartType="test_chart"
+ errorComponent={CustomErrorComponent}
+ />,
+ );
+
+ const customError = await findByTestId('custom-error');
+ expect(customError).toBeInTheDocument();
+ expect(customError).toHaveTextContent('Custom: Custom error message');
+});
diff --git
a/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
b/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
index ba22e64808..83ddb688b9 100644
---
a/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
+++
b/superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
@@ -25,6 +25,7 @@ import {
SupersetClientInterface,
buildQueryContext,
RequestConfig,
+ getClientErrorObject,
} from '../..';
import { Loading } from '../../components/Loading';
import ChartClient from '../clients/ChartClient';
@@ -279,11 +280,17 @@ export default function StatefulChart(props:
StatefulChartProps) {
}
} catch (err) {
// Ignore abort errors
- if (err.name === 'AbortError') {
+ if ((err as Error).name === 'AbortError') {
return;
}
- const errorObj = err as Error;
+ const parsedError = await getClientErrorObject(
+ err as Parameters<typeof getClientErrorObject>[0],
+ );
+ const errorMessage =
+ parsedError.error || parsedError.message || 'An error occurred';
+
+ const errorObj = new Error(errorMessage);
setStatus('error');
setError(errorObj);