From b6c5910f0b0711ded8857f4785c51332455139f1 Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:40:54 +0000 Subject: [PATCH 1/2] fix(seer): Handle non-2xx HTTP responses from severity-score endpoint --- src/sentry/event_manager.py | 4 +++ tests/sentry/event_manager/test_severity.py | 37 +++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/sentry/event_manager.py b/src/sentry/event_manager.py index f0027b89b53f..0af0dcfb6866 100644 --- a/src/sentry/event_manager.py +++ b/src/sentry/event_manager.py @@ -2226,6 +2226,10 @@ def _get_severity_score(event: Event) -> tuple[float, str]: timeout=timeout, viewer_context=viewer_context, ) + if response.status >= 400: + raise Exception( + f"Seer severity endpoint returned HTTP {response.status}" + ) severity = orjson.loads(response.data).get("severity") reason = "ml" except MaxRetryError: diff --git a/tests/sentry/event_manager/test_severity.py b/tests/sentry/event_manager/test_severity.py index cb3043301192..62d295d2b7d0 100644 --- a/tests/sentry/event_manager/test_severity.py +++ b/tests/sentry/event_manager/test_severity.py @@ -293,6 +293,43 @@ def test_timeout_error( assert reason == "microservice_timeout" assert cache.get(SEER_ERROR_COUNT_KEY) == 1 + @patch( + "sentry.event_manager.severity_connection_pool.urlopen", + return_value=HTTPResponse(body=b"Service Unavailable", status=503), + ) + @patch("sentry.event_manager.sentry_sdk.capture_exception") + @patch("sentry.event_manager.metrics.incr") + def test_http_error_response( + self, + mock_metrics_incr: MagicMock, + mock_capture_exception: MagicMock, + _mock_urlopen: MagicMock, + ) -> None: + """A non-2xx HTTP response (e.g. 503) should be handled gracefully without raising JSONDecodeError.""" + manager = EventManager( + make_event( + exception={ + "values": [ + { + "type": "NopeError", + "value": "Nopey McNopeface", + "mechanism": {"type": "generic", "handled": True}, + } + ] + }, + platform="python", + ) + ) + event = manager.save(self.project.id) + + severity, reason = _get_severity_score(event) + + mock_capture_exception.assert_called_once_with() + mock_metrics_incr.assert_any_call("issues.severity.error", tags={"reason": "unknown"}) + assert severity == 1.0 + assert reason == "microservice_error" + assert cache.get(SEER_ERROR_COUNT_KEY) == 1 + @patch( "sentry.event_manager.severity_connection_pool.urlopen", side_effect=Exception("It broke"), From 79cd50fc1f5ec0a42a178e128951efeb3ea3116f Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:41:43 +0000 Subject: [PATCH 2/2] :hammer_and_wrench: apply pre-commit fixes --- src/sentry/event_manager.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sentry/event_manager.py b/src/sentry/event_manager.py index 0af0dcfb6866..8e30cc9daa20 100644 --- a/src/sentry/event_manager.py +++ b/src/sentry/event_manager.py @@ -2227,9 +2227,7 @@ def _get_severity_score(event: Event) -> tuple[float, str]: viewer_context=viewer_context, ) if response.status >= 400: - raise Exception( - f"Seer severity endpoint returned HTTP {response.status}" - ) + raise Exception(f"Seer severity endpoint returned HTTP {response.status}") severity = orjson.loads(response.data).get("severity") reason = "ml" except MaxRetryError: