Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/sentry/explore/endpoints/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rest_framework.serializers import ListField

from sentry.constants import ALL_ACCESS_PROJECTS
from sentry.discover.arithmetic import is_equation
from sentry.explore.models import ExploreSavedQueryDataset
from sentry.utils.dates import parse_stats_period, validate_interval

Expand Down Expand Up @@ -222,9 +223,16 @@
raise serializers.ValidationError(
"Metric field is only allowed for metrics dataset"
)
if data["dataset"] == "metrics" and "metric" not in q:

# the metrics field is only required for non-equation queries
has_equations = any(
is_equation(y_axis)
for aggregate_field in q.get("aggregateField", [])

Check warning on line 230 in src/sentry/explore/endpoints/serializers.py

View check run for this annotation

@sentry/warden / warden: sentry-backend-bugs

TypeError when iterating over None aggregateField

When `aggregateField` is explicitly `None` (allowed by `allow_null=True` on line 115), `q.get("aggregateField", [])` returns `None` instead of `[]`. The generator expression then attempts to iterate over `None`, raising `TypeError: 'NoneType' object is not iterable`. This will cause a 500 error when saving explore queries with `aggregateField: null` on the metrics dataset.
for y_axis in aggregate_field.get("yAxes", [])
)
if data["dataset"] == "metrics" and not has_equations and "metric" not in q:
raise serializers.ValidationError(
"Metric field is required for metrics dataset"
"Metric field is required for non-equation queries on the metrics dataset"
)
inner_query = {}
for key in inner_query_keys:
Expand Down
22 changes: 22 additions & 0 deletions tests/sentry/explore/endpoints/test_explore_saved_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -1391,3 +1391,25 @@ def test_post_with_empty_query_is_rejected(self) -> None:
},
)
assert response.status_code == 400

def test_post_with_equation_is_accepted(self) -> None:
with self.feature(self.features):
response = self.client.post(
self.url,
{
"name": "Equation query",
"projects": self.project_ids,
"dataset": "metrics",
"query": [
{
"aggregateField": [{"yAxes": ["equation|A + B"], "chartType": 1}],
"mode": "samples",
"fields": ["A", "B"],
"orderby": "-timestamp",
},
],
},
)
assert response.status_code == 201, response.content
data = response.data
assert data["query"][0].get("metric") is None
Loading