You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Slack adapter: unfurl wait blocks webhook handling up to 2s per link (4s for edits) #1132
@chat-adapter/slack 4.39.0 waits up to 2 seconds for link-preview (unfurl) data on every incoming message that contains a link with no cached preview. The wait runs inside webhook handling, before the event reaches the app. Links Slack never unfurls (internal admin URLs, bot posts sent with unfurl_links: false) always wait the full 2 seconds. A message_changed event parses both the old and the new text, so an edit waits twice.
Impact
Hosts that must answer Slack's webhook within a fixed window can't accept these events. We run Paperclip, which gives the SDK 2.5 seconds, so every message with an unpreviewed link and every edit gets a 503 on each retry and is eventually dropped.
Measurements
Live adapter, real bot token, one bot post with a link:
as sent: 2,137 ms in the adapter (14 state reads of slack:unfurls:<ts>, 150 ms apart)
same post with the link removed: 33 ms
an edit of that post: 4,245 ms
Where
enrichLinks with UNFURL_WAIT_MS = 2e3, polling chat state every 150 ms. It looks like this arrived with the link-preview work in #395.
Suggested fix
Don't block webhook handling on unfurls: read the cached unfurl once and move on, or make the wait configurable (0 to disable). Setting UNFURL_WAIT_MS to 0 fixed it for us; one read takes about 0 ms.
I reproduced the delay on published @chat-adapter/slack, @chat-adapter/state-memory, and chat 4.44.0 with Node 24.18.0. The adapter returned HTTP 200 before the queued processing finished. A host that waits for the waitUntil tasks before replying would still include the polling delay in its response time.
Synthetic event
Time to HTTP 200
Time through completion of all queued tasks
Message without a link
6 ms
13 ms
Message with an uncached link
2 ms
2,071 ms
Edit with an uncached link in both snapshots
3 ms
4,117 ms
Message with a cached link
3 ms
6 ms
Each case invoked its handler once. The cache-hit control also confirmed that the handler received the cached title. These are local measurements with in-memory state and synthetic signed requests. The probe measures the adapter boundary and leaves Paperclip's integration untested.
The edit result is consistent with processMessageUpdated resolving the new and previous snapshots sequentially. Both use the same Slack parser and unfurl polling.
Offline reproduction
In an empty directory with Node 24, install the three pinned packages, save the script as repro.mjs, and run node repro.mjs.
Activity
shpetimhaxhiu commentedon Nov 11, 2026
I reproduced the delay on published
@chat-adapter/slack,@chat-adapter/state-memory, andchat4.44.0 with Node 24.18.0. The adapter returned HTTP 200 before the queued processing finished. A host that waits for thewaitUntiltasks before replying would still include the polling delay in its response time.Each case invoked its handler once. The cache-hit control also confirmed that the handler received the cached title. These are local measurements with in-memory state and synthetic signed requests. The probe measures the adapter boundary and leaves Paperclip's integration untested.
The edit result is consistent with
processMessageUpdatedresolving the new and previous snapshots sequentially. Both use the same Slack parser and unfurl polling.Offline reproduction
In an empty directory with Node 24, install the three pinned packages, save the script as
repro.mjs, and runnode repro.mjs.I used Codex to prepare and run this reproduction.