diff --git a/products/warehouse_sources/backend/models/table.py b/products/warehouse_sources/backend/models/table.py index fbd22bc1df91..acea21d52e81 100644 --- a/products/warehouse_sources/backend/models/table.py +++ b/products/warehouse_sources/backend/models/table.py @@ -30,7 +30,12 @@ from posthog.clickhouse.client import sync_execute from posthog.clickhouse.query_tagging import Feature, Product, tag_queries -from posthog.errors import CORRUPTED_PARQUET_METADATA_MESSAGE, wrap_clickhouse_query_error +from posthog.errors import ( + CORRUPTED_PARQUET_METADATA_MESSAGE, + QueryErrorCategory, + classify_query_error, + wrap_clickhouse_query_error, +) from posthog.exceptions_capture import capture_exception from posthog.models.utils import CreatedMetaFields, DeletedMetaFields, UpdatedMetaFields, UUIDTModel, sane_repr from posthog.schema_enums import DatabaseSerializedFieldType @@ -932,6 +937,13 @@ def _safe_expose_ch_error(self, err): if not hasattr(err, "message"): raise err + # A cancelled query here means our own client timed out reading, not a bad file or bucket. + if classify_query_error(err) == QueryErrorCategory.CANCELLED: + raise Exception( + "Reading the files from your storage bucket took too long and the query was cancelled. " + "This is usually temporary - try again, or narrow the URL pattern if the dataset is very large." + ) + for key, value in ExtractErrors.items(): if key in raw_message: raise Exception(value) diff --git a/products/warehouse_sources/backend/tests/test_table.py b/products/warehouse_sources/backend/tests/test_table.py index b89131ce3241..00cbfd2246be 100644 --- a/products/warehouse_sources/backend/tests/test_table.py +++ b/products/warehouse_sources/backend/tests/test_table.py @@ -140,6 +140,11 @@ def test_transient_errors_without_message_are_reraised_untouched(self, err: Exce DataWarehouseTable()._safe_expose_ch_error(err) assert exc_info.value is err + def test_cancelled_query_gets_a_timeout_message_instead_of_storage_bucket_blame(self) -> None: + # code 394 QUERY_WAS_CANCELLED here means our own client timed out reading, not bad files. + with pytest.raises(Exception, match="took too long"): + DataWarehouseTable()._safe_expose_ch_error(ServerException("DB::Exception: Query was cancelled.", code=394)) + def test_delta_kernel_permission_error_gets_actionable_message(self) -> None: # Delta-format tables (the default for every warehouse_sources synced table) read via # ClickHouse's DeltaLake kernel, whose object_store errors use different wording than