You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by rb...@apache.org on 2026/03/19 14:37:36 UTC

(superset) 01/01: fix(chart): add error logging to /api/v1/chart/data endpoint

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

rbenitez pushed a commit to branch rebenitez1802/fix/add-debug-logs-to-chart-data-endpoint
in repository https://gitbox.apache.org/repos/asf/superset.git

commit c21321dfa2cd631208fea07b0f500f4347413dc0
Author: Rafael Benitez <re...@gmail.com>
AuthorDate: Thu Mar 19 11:37:09 2026 -0300

    fix(chart): add error logging to /api/v1/chart/data endpoint
    
    Add error-level logging to all failure paths in the chart data API
    to help diagnose intermittent 400 BAD REQUEST failures during CSV
    exports. Previously, JSON parsing errors were silently swallowed by
    contextlib.suppress and validation/query errors returned 400 without
    any logging, making it impossible to identify which failure path was
    hit.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 superset/charts/data/api.py | 69 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/superset/charts/data/api.py b/superset/charts/data/api.py
index 707ce79f918..93c754c8906 100644
--- a/superset/charts/data/api.py
+++ b/superset/charts/data/api.py
@@ -250,9 +250,29 @@ class ChartDataRestApi(ChartRestApi):
             json_body = request.json
         elif request.form.get("form_data"):
             # CSV export submits regular form data
-            with contextlib.suppress(TypeError, json.JSONDecodeError):
+            try:
                 json_body = json.loads(request.form["form_data"])
+            except (TypeError, json.JSONDecodeError):
+                logger.error(
+                    "Failed to parse form_data JSON: "
+                    "content_type=%s, content_length=%s, form_data_length=%s, "
+                    "referrer=%s",
+                    request.content_type,
+                    request.content_length,
+                    len(request.form.get("form_data", "")),
+                    request.referrer,
+                )
         if json_body is None:
+            logger.error(
+                "Chart data request rejected: json_body is None. "
+                "is_json=%s, content_type=%s, content_length=%s, "
+                "has_form_data=%s, referrer=%s",
+                request.is_json,
+                request.content_type,
+                request.content_length,
+                bool(request.form.get("form_data")),
+                request.referrer,
+            )
             return self.response_400(message=_("Request is not JSON"))
 
         try:
@@ -260,10 +280,37 @@ class ChartDataRestApi(ChartRestApi):
             command = ChartDataCommand(query_context)
             command.validate()
         except DatasourceNotFound:
+            logger.error(
+                "Chart data request: DatasourceNotFound. "
+                "datasource=%s, result_format=%s, "
+                "slice_id=%s, referrer=%s",
+                json_body.get("datasource"),
+                json_body.get("result_format"),
+                json_body.get("form_data", {}).get("slice_id"),
+                request.referrer,
+            )
             return self.response_404()
         except QueryObjectValidationError as error:
+            logger.error(
+                "Chart data request: QueryObjectValidationError: %s. "
+                "result_format=%s, slice_id=%s, referrer=%s",
+                error.message,
+                json_body.get("result_format"),
+                json_body.get("form_data", {}).get("slice_id"),
+                request.referrer,
+            )
             return self.response_400(message=error.message)
         except ValidationError as error:
+            logger.error(
+                "Chart data request: ValidationError: %s. "
+                "result_format=%s, datasource=%s, "
+                "slice_id=%s, referrer=%s",
+                error.normalized_messages(),
+                json_body.get("result_format"),
+                json_body.get("datasource"),
+                json_body.get("form_data", {}).get("slice_id"),
+                request.referrer,
+            )
             return self.response_400(
                 message=_(
                     "Request is incorrect: %(error)s", error=error.normalized_messages()
@@ -413,9 +460,21 @@ class ChartDataRestApi(ChartRestApi):
             else:
                 has_export_perm = security_manager.can_access("can_csv", "Superset")
             if not has_export_perm:
+                logger.error(
+                    "Chart data request: export permission denied. "
+                    "result_format=%s, referrer=%s",
+                    result_format,
+                    request.referrer,
+                )
                 return self.response_403()
 
             if not result["queries"]:
+                logger.error(
+                    "Chart data request: empty query result. "
+                    "result_format=%s, referrer=%s",
+                    result_format,
+                    request.referrer,
+                )
                 return self.response_400(_("Empty query result"))
 
             is_csv_format = result_format == ChartDataResultFormat.CSV
@@ -504,6 +563,14 @@ class ChartDataRestApi(ChartRestApi):
         except ChartDataCacheLoadError as exc:
             return self.response_422(message=exc.message)
         except ChartDataQueryFailedError as exc:
+            logger.error(
+                "Chart data query failed: %s. "
+                "result_format=%s, force_cached=%s, referrer=%s",
+                exc.message,
+                form_data.get("result_format") if form_data else None,
+                force_cached,
+                request.referrer,
+            )
             return self.response_400(message=exc.message)
 
             # Log is_cached if extra payload callback is provided