diff --git a/ee/clickhouse/errors.py b/ee/clickhouse/errors.py index 98645cca3e22c..ec91f20e45a03 100644 --- a/ee/clickhouse/errors.py +++ b/ee/clickhouse/errors.py @@ -5,6 +5,10 @@ from posthog.exceptions import EstimatedQueryExecutionTimeTooLong +class CHQueryErrorCannotCompileRegexp(ServerException): + pass + + def wrap_query_error(err: Exception) -> Exception: "Beautifies clickhouse client errors, using custom error classes for every code" if not isinstance(err, ServerException): @@ -17,6 +21,11 @@ def wrap_query_error(err: Exception) -> Exception: # :TRICKY: Return a custom class for every code by looking up the short name and creating a class dynamically. if hasattr(err, "code"): + # Most errors are generated dynamically, except the ones we want to + # catch elsewhere in code. + if err.code == 427: + return CHQueryErrorCannotCompileRegexp(err.message, code=err.code) + name = CLICKHOUSE_ERROR_CODE_LOOKUP.get(err.code, "UNKNOWN") name = f"CHQueryError{name.replace('_', ' ').title().replace(' ', '')}" return type(name, (ServerException,), {})(err.message, code=err.code) diff --git a/ee/clickhouse/views/actions.py b/ee/clickhouse/views/actions.py index a3f880f465749..b2faa58925e8f 100644 --- a/ee/clickhouse/views/actions.py +++ b/ee/clickhouse/views/actions.py @@ -4,11 +4,13 @@ from rest_framework import serializers from rest_framework.decorators import action +from rest_framework.exceptions import ValidationError from rest_framework.request import Request from rest_framework.response import Response from rest_framework_csv import renderers as csvrenderers from ee.clickhouse.client import sync_execute +from ee.clickhouse.errors import CHQueryErrorCannotCompileRegexp from ee.clickhouse.models.action import format_action_filter from ee.clickhouse.queries.trends.person import TrendsPersonQuery from ee.clickhouse.sql.person import INSERT_COHORT_ALL_PEOPLE_THROUGH_PERSON_ID, PERSON_STATIC_COHORT_TABLE @@ -90,10 +92,15 @@ def count(self, request: Request, **kwargs) -> Response: # type: ignore if query == "": return Response({"count": 0}) - results = sync_execute( - "SELECT count(1) FROM events WHERE team_id = %(team_id)s AND {}".format(query), - {"team_id": action.team_id, **params}, - ) + try: + results = sync_execute( + "SELECT count(1) FROM events WHERE team_id = %(team_id)s AND {}".format(query), + {"team_id": action.team_id, **params}, + ) + except CHQueryErrorCannotCompileRegexp: + raise ValidationError( + "Invalid filters for action count. Check that your selectors and regexes are defined properly." + ) return Response({"count": results[0][0]}) diff --git a/ee/clickhouse/views/events.py b/ee/clickhouse/views/events.py index 48d41b8ee1c6c..e8f3053068100 100644 --- a/ee/clickhouse/views/events.py +++ b/ee/clickhouse/views/events.py @@ -4,11 +4,12 @@ from django.utils.timezone import now from rest_framework.decorators import action -from rest_framework.exceptions import NotFound +from rest_framework.exceptions import NotFound, ValidationError from rest_framework.request import Request from rest_framework.response import Response from ee.clickhouse.client import sync_execute +from ee.clickhouse.errors import CHQueryErrorCannotCompileRegexp from ee.clickhouse.models.action import format_action_filter from ee.clickhouse.models.event import ClickhouseEventSerializer, determine_event_conditions from ee.clickhouse.models.person import get_persons_by_distinct_ids @@ -100,7 +101,12 @@ def list(self, request: Request, *args: Any, **kwargs: Any) -> Response: team = self.team filter = Filter(request=request, team=self.team) - query_result = self._query_events_list(filter, team, request, limit=limit) + try: + query_result = self._query_events_list(filter, team, request, limit=limit) + except CHQueryErrorCannotCompileRegexp: + raise ValidationError( + "Invalid filter for events. Check that your selectors and regexes are defined properly." + ) # Retry the query without the 1 day optimization if len(query_result) < limit and not request.GET.get("after"): diff --git a/frontend/src/scenes/events/eventsTableLogic.ts b/frontend/src/scenes/events/eventsTableLogic.ts index 2572ec70e4925..761b44f94a512 100644 --- a/frontend/src/scenes/events/eventsTableLogic.ts +++ b/frontend/src/scenes/events/eventsTableLogic.ts @@ -299,7 +299,7 @@ export const eventsTableLogic = kea