diff --git a/src/sentry/api/endpoints/organization_events_stats.py b/src/sentry/api/endpoints/organization_events_stats.py index f042624ba95d..6a3fd99ee188 100644 --- a/src/sentry/api/endpoints/organization_events_stats.py +++ b/src/sentry/api/endpoints/organization_events_stats.py @@ -29,6 +29,7 @@ get_trace_metric_from_request, ) from sentry.search.eap.types import SearchResolverConfig +from sentry.search.events.fields import is_function from sentry.search.events.types import SnubaParams from sentry.snuba import ( discover, @@ -305,6 +306,8 @@ def get_rpc_config(): if "timestamp" in raw_groupby: raise ParseError("Cannot group by timestamp") if use_rpc: + if all(is_function(column) for column in raw_groupby): + raise ParseError("topEvents requires at least one non-aggregate field") return scoped_dataset.run_top_events_timeseries_query( params=snuba_params, query_string=query, diff --git a/tests/snuba/api/endpoints/test_organization_events_stats_span_indexed.py b/tests/snuba/api/endpoints/test_organization_events_stats_span_indexed.py index 5728571ed1af..792fd67b711b 100644 --- a/tests/snuba/api/endpoints/test_organization_events_stats_span_indexed.py +++ b/tests/snuba/api/endpoints/test_organization_events_stats_span_indexed.py @@ -719,6 +719,32 @@ def test_top_events_with_no_data(self) -> None: ) assert response.status_code == 200, response.content + def test_top_events_without_groupby(self) -> None: + self.store_spans( + [ + self.create_span( + {"sentry_tags": {"op": "db"}}, + start_ts=self.day_ago + timedelta(minutes=1), + ), + ], + ) + + response = self._do_request( + data={ + "start": self.day_ago, + "end": self.day_ago + timedelta(minutes=6), + "interval": "1m", + "yAxis": "p95(span.duration)", + "field": ["p95(span.duration)"], + "query": "span.op:db", + "dataset": "spans", + "excludeOther": 0, + "topEvents": 10, + }, + ) + assert response.status_code == 400, response.content + assert response.data["detail"] == "topEvents requires at least one non-aggregate field" + def test_count_unique_nans(self) -> None: self.store_span( self.create_span(start_ts=self.two_days_ago + timedelta(minutes=1)),