You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2026/09/26 16:52:06 UTC

(superset) 01/01: fix(dashboard): catch JSONDecodeError on malformed default_filters in set_dash_metadata

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

eschutho pushed a commit to branch fix-dashboard-default-filters-decode-error
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 0e36fa4c86ca03c0bf78b861da03f5e9103f4195
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Sat Sep 26 16:51:53 2026 +0000

    fix(dashboard): catch JSONDecodeError on malformed default_filters in set_dash_metadata
    
    DashboardJSONMetadataSchema.default_filters only validates that the value
    is a string, so a non-JSON string reaches DashboardDAO.set_dash_metadata
    via the dashboard create/update API and escapes as a raw JSONDecodeError
    (returned as a 500). Fall back to an empty dict, mirroring the existing
    idiom in DashboardDAO.update_native_filters_config.
    
    Co-Authored-By: Claude Opus 5.5 <no...@anthropic.com>
---
 superset/daos/dashboard.py             |  7 +++++--
 tests/unit_tests/dao/dashboard_test.py | 23 +++++++++++++++++++++++
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/superset/daos/dashboard.py b/superset/daos/dashboard.py
index 6d323cd0717..c48f936eabf 100644
--- a/superset/daos/dashboard.py
+++ b/superset/daos/dashboard.py
@@ -322,7 +322,7 @@ class DashboardDAO(BaseDAO[Dashboard]):
         return True
 
     @staticmethod
-    def set_dash_metadata(
+    def set_dash_metadata(  # noqa: C901
         dashboard: Dashboard,
         data: dict[Any, Any],
         old_to_new_slice_ids: dict[int, int] | None = None,
@@ -413,7 +413,10 @@ class DashboardDAO(BaseDAO[Dashboard]):
                     else data["filter_scopes"],
                 )
 
-            default_filters_data = json.loads(data.get("default_filters", "{}"))
+            try:
+                default_filters_data = json.loads(data.get("default_filters", "{}"))
+            except (json.JSONDecodeError, TypeError):
+                default_filters_data = {}
             applicable_filters = {
                 key: v
                 for key, v in default_filters_data.items()
diff --git a/tests/unit_tests/dao/dashboard_test.py b/tests/unit_tests/dao/dashboard_test.py
index 830cb2feef8..48b617a1370 100644
--- a/tests/unit_tests/dao/dashboard_test.py
+++ b/tests/unit_tests/dao/dashboard_test.py
@@ -172,6 +172,29 @@ def test_set_dash_metadata_updates_refresh_frequency_when_present(
     )
 
 
+def test_set_dash_metadata_malformed_default_filters(session: Session) -> None:
+    """set_dash_metadata must not raise on a ``default_filters`` value that is
+    not valid JSON.
+
+    ``DashboardJSONMetadataSchema.default_filters`` only checks that the value
+    is a string, so malformed JSON reaches ``set_dash_metadata`` via the
+    dashboard create/update API and previously escaped as a raw
+    ``JSONDecodeError``.
+    """
+    Dashboard.metadata.create_all(session.get_bind())
+
+    dashboard = Dashboard(dashboard_title="malformed_default_filters_dash")
+    db.session.add(dashboard)
+    db.session.flush()
+
+    DashboardDAO.set_dash_metadata(
+        dashboard, {"positions": {}, "default_filters": "not-json"}
+    )
+
+    md = json.loads(dashboard.json_metadata)
+    assert md["default_filters"] == "{}"
+
+
 def _position_with_trapped_chart(
     placed_chart_id: int, trapped_chart_id: int
 ) -> dict[str, Any]: