This is an automated email from the ASF dual-hosted git repository.
eladkal pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new e248b24a376 Validate `thread_ts` requires single channel in
`SlackAPIFileOperator` (#63523)
e248b24a376 is described below
commit e248b24a376922559cbd80cffdb44463f6cb2928
Author: yuseok89 <[email protected]>
AuthorDate: Sat Mar 14 23:39:44 2026 +0900
Validate `thread_ts` requires single channel in `SlackAPIFileOperator`
(#63523)
---
providers/slack/src/airflow/providers/slack/hooks/slack.py | 6 ++++++
providers/slack/src/airflow/providers/slack/operators/slack.py | 4 ++--
providers/slack/tests/unit/slack/hooks/test_slack.py | 10 ++++++++++
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/providers/slack/src/airflow/providers/slack/hooks/slack.py
b/providers/slack/src/airflow/providers/slack/hooks/slack.py
index ac6d83c518f..2a5f79339a4 100644
--- a/providers/slack/src/airflow/providers/slack/hooks/slack.py
+++ b/providers/slack/src/airflow/providers/slack/hooks/slack.py
@@ -310,6 +310,12 @@ class SlackHook(BaseHook):
else:
channels_to_share = [None]
+ if thread_ts is not None and len(channels_to_share) > 1:
+ raise ValueError(
+ "thread_ts cannot be used with multiple channels. "
+ "A thread belongs to a single channel; specify exactly one
channel when replying in a thread."
+ )
+
responses = []
for channel in channels_to_share:
responses.append(
diff --git a/providers/slack/src/airflow/providers/slack/operators/slack.py
b/providers/slack/src/airflow/providers/slack/operators/slack.py
index 56b4c90a387..421ebfb8c9b 100644
--- a/providers/slack/src/airflow/providers/slack/operators/slack.py
+++ b/providers/slack/src/airflow/providers/slack/operators/slack.py
@@ -228,8 +228,8 @@ class SlackAPIFileOperator(SlackAPIOperator):
:param snippet_type: Syntax type for the snippet being uploaded.(templated)
:param method_version: The version of the method of Slack SDK Client to be
used, either "v1" or "v2".
:param thread_ts: Provide another message's ``ts`` value to upload the
file as a reply in a
- thread. See https://api.slack.com/messaging#threading (templated)
-
+ thread. See https://api.slack.com/messaging#threading. When using
``thread_ts``, specify
+ exactly one channel in ``channels``; a thread belongs to a single
channel. (templated)
:return: List of Slack API response data from ``files_upload_v2`` (one per
channel).
Returned value is pushed to XCom for downstream tasks.
"""
diff --git a/providers/slack/tests/unit/slack/hooks/test_slack.py
b/providers/slack/tests/unit/slack/hooks/test_slack.py
index 1de8c06a0ea..3e7d94df33f 100644
--- a/providers/slack/tests/unit/slack/hooks/test_slack.py
+++ b/providers/slack/tests/unit/slack/hooks/test_slack.py
@@ -567,6 +567,16 @@ class TestSlackHook:
hook.send_file_v1_to_v2(channels=channels, content="Fake")
assert mocked_send_file_v2.call_count == expected_calls
+ def test_send_file_v1_to_v2_thread_ts_with_multiple_channels_raises(self):
+ """thread_ts with multiple channels is invalid; a thread belongs to
one channel."""
+ hook = SlackHook(slack_conn_id=SLACK_API_DEFAULT_CONN_ID)
+ with pytest.raises(ValueError, match="thread_ts.*single channel"):
+ hook.send_file_v1_to_v2(
+ channels="#general,#random",
+ content="Fake",
+ thread_ts="1234567890.123456",
+ )
+
class TestSlackHookAsync:
@pytest.fixture