diff --git a/src/sentry/spans/consumers/process_segments/message.py b/src/sentry/spans/consumers/process_segments/message.py index 7c0bf9f27193..0b42cac84938 100644 --- a/src/sentry/spans/consumers/process_segments/message.py +++ b/src/sentry/spans/consumers/process_segments/message.py @@ -134,7 +134,10 @@ def _process_segment( return [] # Always attempt title generation, even when enrichment is skipped below. - spawn_conversation_title_generation(unprocessed_spans, project) + 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"