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/20 15:11:59 UTC
(superset) 01/01: fix(mcp): catch ValueError for reversed date range in query_dataset
This is an automated email from the ASF dual-hosted git repository.
eschutho pushed a commit to branch fix-mcp-query-dataset-reversed-date-range
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 3d119c5d1058306e6dfdafc02af878dac4ecadfe
Author: Elizabeth Thompson <es...@gmail.com>
AuthorDate: Sun Sep 20 15:11:44 2026 +0000
fix(mcp): catch ValueError for reversed date range in query_dataset
---
superset/mcp_service/dataset/tool/query_dataset.py | 11 +++++
.../mcp_service/dataset/tool/test_query_dataset.py | 52 ++++++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/superset/mcp_service/dataset/tool/query_dataset.py b/superset/mcp_service/dataset/tool/query_dataset.py
index f49dc158605..9cd12bfabaf 100644
--- a/superset/mcp_service/dataset/tool/query_dataset.py
+++ b/superset/mcp_service/dataset/tool/query_dataset.py
@@ -433,6 +433,17 @@ async def query_dataset( # noqa: C901
error_type="DatabaseError",
)
+ except ValueError as exc:
+ # Expected user/agent-input validation (e.g. a reversed time_range where
+ # since > until raises "From date cannot be larger than to date" from
+ # date_parser.get_since_until). Return an actionable ValidationError
+ # without a full-traceback log — this is not a bug.
+ await ctx.error("Invalid request: %s" % (str(exc),))
+ return DatasetError.create(
+ error=str(exc),
+ error_type="ValidationError",
+ )
+
except Exception as exc:
logger.exception(
"Unexpected error while querying dataset: %s: %s",
diff --git a/tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py b/tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
index a4513a0a671..a055f08a4e0 100644
--- a/tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
+++ b/tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.py
@@ -435,6 +435,58 @@ async def test_query_dataset_time_range_no_temporal_column(mcp_server: FastMCP)
assert "temporal column" in data["error"].lower()
+@pytest.mark.asyncio
+async def test_query_dataset_reversed_time_range(mcp_server: FastMCP) -> None:
+ """A reversed explicit time_range (since > until) resolves to a clean
+ ValidationError rather than a generic UnexpectedError.
+
+ An explicit ``"<start> : <end>"`` range where start > end passes the
+ pydantic-level validate_time_range guard unchanged (by design) and reaches
+ the real get_since_until(), which raises
+ ``ValueError("From date cannot be larger than to date")``. The tool must
+ surface that as an actionable ValidationError, not swallow it into the
+ catch-all UnexpectedError arm.
+ """
+ dataset = _make_dataset(main_dttm_col="order_date")
+ reversed_range = "2024-01-01T00:00:00 : 2020-01-01T00:00:00"
+
+ def create_with_real_parser(**kwargs):
+ # Exercise the real parser on the reversed range exactly as the query
+ # pipeline would, letting its genuine ValueError propagate.
+ for query in kwargs.get("queries", []):
+ for filt in query.get("filters", []):
+ if filt.get("op") == "TEMPORAL_RANGE":
+ get_since_until(time_range=filt["val"])
+ return MagicMock()
+
+ with (
+ patch.object(
+ query_dataset_module,
+ "resolve_dataset",
+ return_value=dataset,
+ ),
+ patch(
+ "superset.common.query_context_factory.QueryContextFactory.create",
+ side_effect=create_with_real_parser,
+ ),
+ ):
+ async with Client(mcp_server) as client:
+ result = await client.call_tool(
+ "query_dataset",
+ {
+ "request": {
+ "dataset_id": 1,
+ "metrics": ["count"],
+ "time_range": reversed_range,
+ }
+ },
+ )
+
+ data = json.loads(result.content[0].text)
+ assert data["error_type"] == "ValidationError"
+ assert "From date cannot be larger than to date" in data["error"]
+
+
@pytest.mark.asyncio
async def test_query_dataset_with_filters(mcp_server: FastMCP) -> None:
"""User-provided filters are passed through to the query."""