From 96a9ad760acb89039962d422e3ac16dfb1cec9c9 Mon Sep 17 00:00:00 2001 From: Swati Tiwari Date: Sun, 15 Feb 2026 10:50:03 +0530 Subject: [PATCH 1/2] Slack connector to support channel IDs alongside names for indexing --- backend/danswer/connectors/slack/connector.py | 32 ++++++++++++++++--- web/src/app/admin/connectors/slack/page.tsx | 9 ++++-- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/backend/danswer/connectors/slack/connector.py b/backend/danswer/connectors/slack/connector.py index 859a9607e10..455f99ac932 100644 --- a/backend/danswer/connectors/slack/connector.py +++ b/backend/danswer/connectors/slack/connector.py @@ -232,6 +232,12 @@ def _default_msg_filter(message: MessageType) -> bool: return False +def _is_channel_id(value: str) -> bool: + """Slack channel IDs start with C (public) or G (private) followed by + alphanumeric characters, e.g. C04ABCDEF12.""" + return bool(re.fullmatch(r"[CG][A-Z0-9]{8,}", value)) + + def filter_channels( all_channels: list[dict[str, Any]], channels_to_connect: list[str] | None, @@ -241,6 +247,7 @@ def filter_channels( return all_channels if regex_enabled: + # regex only applies to channel names return [ channel for channel in all_channels @@ -250,19 +257,34 @@ def filter_channels( ) ] - # validate that all channels in `channels_to_connect` are valid + # separate channel IDs from channel names + channel_ids = {c for c in channels_to_connect if _is_channel_id(c)} + channel_names = {c for c in channels_to_connect if not _is_channel_id(c)} + + # validate that all channel names are valid # fail loudly in the case of an invalid channel so that the user # knows that one of the channels they've specified is typo'd or private all_channel_names = {channel["name"] for channel in all_channels} - for channel in channels_to_connect: - if channel not in all_channel_names: + for name in channel_names: + if name not in all_channel_names: raise ValueError( - f"Channel '{channel}' not found in workspace. " + f"Channel '{name}' not found in workspace. " f"Available channels: {all_channel_names}" ) + # validate that all channel IDs are valid + all_channel_ids = {channel["id"] for channel in all_channels} + for cid in channel_ids: + if cid not in all_channel_ids: + raise ValueError( + f"Channel ID '{cid}' not found in workspace. " + f"Available channel IDs: {all_channel_ids}" + ) + return [ - channel for channel in all_channels if channel["name"] in channels_to_connect + channel + for channel in all_channels + if channel["name"] in channel_names or channel["id"] in channel_ids ] diff --git a/web/src/app/admin/connectors/slack/page.tsx b/web/src/app/admin/connectors/slack/page.tsx index 3b3cc678169..e8d6f82306a 100644 --- a/web/src/app/admin/connectors/slack/page.tsx +++ b/web/src/app/admin/connectors/slack/page.tsx @@ -228,8 +228,9 @@ const MainSection = () => { name: "channels", label: "Channels:", subtext: ` - Specify 0 or more channels to index. For example, specifying the channel - "support" will cause us to only index all content within the "#support" channel. + Specify 0 or more channels to index by name or channel ID. For example, + specifying "support" or "C04ABCDEF12" will index that channel. + Using channel IDs is recommended as they remain stable even if a channel is renamed. If no channels are specified, all channels in your workspace will be indexed.`, })(values)} { "Please enter the workspace to index" ), channels: Yup.array() - .of(Yup.string().required("Channel names must be strings")) + .of( + Yup.string().required("Channel names or IDs must be strings") + ) .required(), channel_regex_enabled: Yup.boolean().required(), })} From a190ddfb9deb9b4f133095071ab5c506b42ba349 Mon Sep 17 00:00:00 2001 From: Swati Tiwari Date: Sun, 15 Feb 2026 13:12:44 +0530 Subject: [PATCH 2/2] warn on invalid channel names --- backend/danswer/connectors/slack/connector.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/backend/danswer/connectors/slack/connector.py b/backend/danswer/connectors/slack/connector.py index 455f99ac932..39576df69dd 100644 --- a/backend/danswer/connectors/slack/connector.py +++ b/backend/danswer/connectors/slack/connector.py @@ -261,19 +261,27 @@ def filter_channels( channel_ids = {c for c in channels_to_connect if _is_channel_id(c)} channel_names = {c for c in channels_to_connect if not _is_channel_id(c)} - # validate that all channel names are valid - # fail loudly in the case of an invalid channel so that the user - # knows that one of the channels they've specified is typo'd or private all_channel_names = {channel["name"] for channel in all_channels} + all_channel_ids = {channel["id"] for channel in all_channels} + + # validate channel names — if a name is not found but valid channel IDs + # were also provided, warn instead of failing (the channel was likely + # renamed and the user also specified its stable ID) for name in channel_names: if name not in all_channel_names: - raise ValueError( - f"Channel '{name}' not found in workspace. " - f"Available channels: {all_channel_names}" - ) + if channel_ids: + logger.warning( + f"Channel '{name}' not found in workspace. " + f"It may have been renamed. " + f"Consider using channel IDs instead for stability." + ) + else: + raise ValueError( + f"Channel '{name}' not found in workspace. " + f"Available channels: {all_channel_names}" + ) # validate that all channel IDs are valid - all_channel_ids = {channel["id"] for channel in all_channels} for cid in channel_ids: if cid not in all_channel_ids: raise ValueError(