Skip to content

Commit 936f24c

Browse files
EngHabuclaude
andauthored
fix: don't report click.Abort/ClickException to Sentry (#1039)
## Summary - `click.Abort`, `click.exceptions.Exit`, and `click.ClickException` are raised on purpose to display user-facing messages (Ctrl+C, declined prompts, missing dependencies, etc.). They are not crashes and shouldn't generate Sentry issues. - This PR adds a small `_is_user_error` filter at the top of `capture_exception` so they short-circuit before any Sentry init/flush. ## Closes - [FLYTE-SDK-H](https://unionai.sentry.io/issues/FLYTE-SDK-H) — `Abort` from `click.confirm` - [FLYTE-SDK-G](https://unionai.sentry.io/issues/FLYTE-SDK-G) — Docker daemon not reachable - [FLYTE-SDK-J](https://unionai.sentry.io/issues/FLYTE-SDK-J) — Timed out waiting for Flyte cluster - [FLYTE-SDK-W](https://unionai.sentry.io/issues/FLYTE-SDK-W) — Timed out waiting for kubeconfig - [FLYTE-SDK-Q](https://unionai.sentry.io/issues/FLYTE-SDK-Q) — Failed to pull image - [FLYTE-SDK-5](https://unionai.sentry.io/issues/FLYTE-SDK-5) — Failed to start container ## Test plan - [x] New unit tests in tests/flyte/test_sentry.py cover the filter (Abort/Exit/ClickException) and verify real errors still report. - [ ] Smoke test \`flyte start devbox\` locally with no docker running — should print the friendly message and not bump Sentry. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Haytham Abuelfutuh <haytham@afutuh.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 660805a commit 936f24c

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

src/flyte/_sentry.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,22 @@ def init() -> None:
6060
logger.debug("Failed to initialize Sentry", exc_info=True)
6161

6262

63+
def _is_user_error(exc: BaseException) -> bool:
64+
"""Errors raised intentionally as user-facing messages — not crash reports."""
65+
try:
66+
import click
67+
68+
if isinstance(exc, (click.Abort, click.exceptions.Exit, click.ClickException)):
69+
return True
70+
except ImportError:
71+
pass
72+
return False
73+
74+
6375
def capture_exception(exc: BaseException) -> None:
6476
"""Capture an exception and send it to Sentry."""
77+
if _is_user_error(exc):
78+
return
6579
try:
6680
init()
6781
import sentry_sdk

tests/flyte/test_sentry.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from unittest import mock
2+
3+
import click
4+
import pytest
5+
6+
from flyte import _sentry
7+
8+
9+
@pytest.mark.parametrize(
10+
"exc",
11+
[
12+
click.Abort(),
13+
click.exceptions.Exit(1),
14+
click.ClickException("docker daemon not running"),
15+
],
16+
)
17+
def test_capture_exception_skips_user_errors(exc):
18+
with mock.patch.object(_sentry, "init") as init_mock:
19+
_sentry.capture_exception(exc)
20+
init_mock.assert_not_called()
21+
22+
23+
def test_capture_exception_reports_real_errors():
24+
with (
25+
mock.patch.object(_sentry, "init"),
26+
mock.patch("sentry_sdk.is_initialized", return_value=True),
27+
mock.patch("sentry_sdk.capture_exception") as capture_mock,
28+
mock.patch("sentry_sdk.flush"),
29+
):
30+
err = RuntimeError("boom")
31+
_sentry.capture_exception(err)
32+
capture_mock.assert_called_once_with(err)
33+
34+
35+
def test_capture_errors_decorator_filters_click_abort():
36+
@_sentry.capture_errors
37+
def fn():
38+
raise click.Abort
39+
40+
with mock.patch.object(_sentry, "init") as init_mock:
41+
with pytest.raises(click.Abort):
42+
fn()
43+
init_mock.assert_not_called()

0 commit comments

Comments
 (0)