From bfd440d2240bb1c70c037041a0be976b9bb85e07 Mon Sep 17 00:00:00 2001 From: Enoch Tang Date: Wed, 28 Oct 2026 16:05:32 -0400 Subject: [PATCH 1/2] fix(spans): Don't drop segments when title generation fails `spawn_conversation_title_generation` runs inside `process_segment`, and nothing caught its errors. When queuing the title task failed (for example `UnicodeEncodeError` on a message with a split emoji), the whole `process_segment` task failed and every span in the segment was dropped. Titles are optional, so catch and log the error and keep processing the segment. Fixes SENTRY-5SB5 Refs STREAM-1999 Co-Authored-By: Claude --- .../spans/consumers/process_segments/message.py | 6 +++++- .../spans/consumers/process_segments/test_message.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sentry/spans/consumers/process_segments/message.py b/src/sentry/spans/consumers/process_segments/message.py index 7c0bf9f27193..b8c9e78827d9 100644 --- a/src/sentry/spans/consumers/process_segments/message.py +++ b/src/sentry/spans/consumers/process_segments/message.py @@ -134,7 +134,11 @@ def _process_segment( return [] # Always attempt title generation, even when enrichment is skipped below. - spawn_conversation_title_generation(unprocessed_spans, project) + # Titles are optional, so a failure here shouldn't drop the segment. + try: + spawn_conversation_title_generation(unprocessed_spans, project) + except Exception: + logger.exception("spans.process_segments.title_generation.error") if skip_enrichment: return [make_compatible(span) for span in unprocessed_spans] diff --git a/tests/sentry/spans/consumers/process_segments/test_message.py b/tests/sentry/spans/consumers/process_segments/test_message.py index 17156bc16b99..37d4e410f172 100644 --- a/tests/sentry/spans/consumers/process_segments/test_message.py +++ b/tests/sentry/spans/consumers/process_segments/test_message.py @@ -185,6 +185,18 @@ def test_enrich_spans_no_segment(self) -> None: assert span["op"] assert span["hash"] + @mock.patch.object(message_module, "spawn_conversation_title_generation") + def test_title_generation_failure_keeps_segment(self, mock_spawn: mock.MagicMock) -> None: + mock_spawn.side_effect = UnicodeEncodeError("utf-8", "hi", 0, 1, "surrogates not allowed") + spans = self.generate_basic_spans() + + with mock.patch.object(message_module.logger, "exception") as mock_log: + processed_spans = process_segment(spans) + + assert len(processed_spans) == len(spans) + mock_spawn.assert_called_once() + mock_log.assert_any_call("spans.process_segments.title_generation.error") + def test_build_shim_event_data_supports_legacy_profile_id(self) -> None: segment_span = build_mock_span(project_id=self.project.id, is_segment=True) segment_span["hash"] = "hashed-segment" From 8d603a954b32635532753f305ba7f6434271d3ee Mon Sep 17 00:00:00 2001 From: Enoch Tang Date: Thu, 29 Oct 2026 13:30:35 -0400 Subject: [PATCH 2/2] comment --- src/sentry/spans/consumers/process_segments/message.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sentry/spans/consumers/process_segments/message.py b/src/sentry/spans/consumers/process_segments/message.py index b8c9e78827d9..0b42cac84938 100644 --- a/src/sentry/spans/consumers/process_segments/message.py +++ b/src/sentry/spans/consumers/process_segments/message.py @@ -134,7 +134,6 @@ def _process_segment( return [] # Always attempt title generation, even when enrichment is skipped below. - # Titles are optional, so a failure here shouldn't drop the segment. try: spawn_conversation_title_generation(unprocessed_spans, project) except Exception: