From d965ba0f2c018038757580ebcf1e48a754f7dff8 Mon Sep 17 00:00:00 2001 From: Bamdad Dashtban Date: Tue, 7 Apr 2026 21:45:42 +0100 Subject: [PATCH] fix: Slack Socket Mode messages silently dropped when team field missing DM events and Enterprise Grid events don't always include the `team` field, causing `translate_message_event` to return None. Now falls back to `user_team` field, then `connection_id`, then "unknown". Also adds debug logging when messages are skipped for easier diagnosis. Co-Authored-By: Claude Opus 4.6 --- .../src/lintel/slack/event_translator.py | 8 +++- .../slack/src/lintel/slack/socket_listener.py | 8 ++++ .../tests/slack/test_event_translator.py | 40 +++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/slack/src/lintel/slack/event_translator.py b/packages/slack/src/lintel/slack/event_translator.py index bc601723..668aea9a 100644 --- a/packages/slack/src/lintel/slack/event_translator.py +++ b/packages/slack/src/lintel/slack/event_translator.py @@ -19,11 +19,15 @@ def translate_message_event( thread_ts = event.get("thread_ts", event.get("ts", "")) channel_id = event.get("channel", "") - team_id = event.get("team", "") + team_id = event.get("team", "") or event.get("user_team", "") - if not all([thread_ts, channel_id, team_id]): + if not thread_ts or not channel_id: return None + # Use connection_id as workspace fallback when team is absent (e.g. DMs) + if not team_id: + team_id = connection_id or "unknown" + return ProcessIncomingMessage( thread_ref=ThreadRef( workspace_id=team_id, diff --git a/packages/slack/src/lintel/slack/socket_listener.py b/packages/slack/src/lintel/slack/socket_listener.py index 12e66f1b..dfe8c32d 100644 --- a/packages/slack/src/lintel/slack/socket_listener.py +++ b/packages/slack/src/lintel/slack/socket_listener.py @@ -123,6 +123,14 @@ async def _on_message(self, event: dict[str, Any]) -> None: cmd = translate_message_event(event, connection_id=self._connection_id) if cmd is None: + logger.debug( + "slack.socket.message_skipped", + has_bot_id=bool(event.get("bot_id")), + subtype=event.get("subtype", ""), + has_team=bool(event.get("team")), + has_channel=bool(event.get("channel")), + event_keys=list(event.keys()), + ) return logger.info( diff --git a/packages/slack/tests/slack/test_event_translator.py b/packages/slack/tests/slack/test_event_translator.py index 9b93cab2..661a28d4 100644 --- a/packages/slack/tests/slack/test_event_translator.py +++ b/packages/slack/tests/slack/test_event_translator.py @@ -74,6 +74,46 @@ def test_returns_none_for_missing_required_fields(self) -> None: event = {"type": "message", "text": "hello"} assert translate_message_event(event) is None + def test_handles_missing_team_with_connection_id(self) -> None: + """DM events may not include team — fallback to connection_id.""" + event = { + "type": "message", + "text": "hi from DM", + "user": "U12345", + "channel": "D99999", + "ts": "1234567890.123456", + } + result = translate_message_event(event, connection_id="channel:slack") + assert result is not None + assert result.thread_ref.workspace_id == "channel:slack" + assert result.raw_text == "hi from DM" + + def test_handles_missing_team_without_connection_id(self) -> None: + event = { + "type": "message", + "text": "hi", + "user": "U12345", + "channel": "D99999", + "ts": "1234567890.123456", + } + result = translate_message_event(event) + assert result is not None + assert result.thread_ref.workspace_id == "unknown" + + def test_uses_user_team_field(self) -> None: + """Enterprise Grid events use user_team instead of team.""" + event = { + "type": "message", + "text": "enterprise msg", + "user": "U12345", + "channel": "C99999", + "user_team": "E11111", + "ts": "1234567890.123456", + } + result = translate_message_event(event) + assert result is not None + assert result.thread_ref.workspace_id == "E11111" + def test_returns_none_for_empty_channel(self) -> None: event = { "type": "message",