Slack dispatch_failed: 7 Ways We Reproduced It, and the 3-Second Fix
We pointed a slash command at a local server and broke it on purpose: HTTP 500, 401 and 302, a wrong path, a dead tunnel, a stopped server and Socket Mode with no process. Each one gave dispatch_failed. A slow reply gave operation_timeout instead.
On this page
dispatch_failed means Slack sent your slash command to the app and did not get a usable reply: the Request URL returned an error status, could not be reached, or the app runs in Socket Mode and no process was connected. We reproduced seven causes on 2 October 2026 with a test app in our own workspace, and each one returned dispatch_failed. A reply that arrives but takes longer than about 3 seconds gives a different error, operation_timeout. The fix for both is the same: return HTTP 200 at once and send the real answer to response_url.
What Slack shows for each failure
Slack web hides the error code for most failures. For an HTTP 500, it posted this, visible only to the person who typed the command, and left the command in the message box:
The error code is in the response to chat.command, the call the Slack client makes when you press Enter. We made the same call from the browser session and got:
{"ok": false, "error": "dispatch_failed"}
A timeout looks different. Slack names the error in the message:
So if you see the "did not respond" text, look for a failed request. If you see operation_timeout, your handler is working but slow.
The causes we reproduced
Our handler was a small Flask app on localhost:8851, reached through a cloudflared quick tunnel. We changed one thing at a time and ran the command:
| What we broke | chat.command response | Time to the error | What our server saw |
|---|---|---|---|
| Handler returns HTTP 500 | dispatch_failed | 0.6 s | the request, then our 500 |
| Handler returns HTTP 401 (what a failed signature check sends) | dispatch_failed | 0.8 s | the request, then our 401 |
| Handler returns HTTP 302 (a redirect, such as http to https) | dispatch_failed | 0.5 s | the request; Slack did not follow it |
Request URL path wrong (/wrong/path) | dispatch_failed | 0.6 s | a 404 for /wrong/path |
| Local server stopped, tunnel still up (the tunnel answered 502) | dispatch_failed | 0.6 s | nothing |
| Tunnel stopped, so the hostname no longer resolved | dispatch_failed | 0.3 s | nothing |
| Socket Mode turned on, no Socket Mode process running | dispatch_failed | 0.3 s | nothing |
| Handler sleeps 2.5 s, then replies | ok | 3.2 s | the request, reply after 2.5 s |
| Handler sleeps 2.8 s, 3.0 s or 4 s, then replies | operation_timeout | 3.4 s | the request; the reply was thrown away |
Three things the table shows:
- • Slack sent each command once. Our log has one request per attempt, with no retries, so a failed command is lost unless the user runs it again.
- • The time budget is shorter than 3 seconds of your own code. Through the tunnel, a 2.5 s handler passed and a 2.8 s handler failed. Network time counts too.
- • Socket Mode and a dead URL give the same code. If your app uses Socket Mode,
dispatch_failedusually means the process that holds the WebSocket is not running; see our Socket Mode in Python test.
For the network causes, open the Request URL from the command's settings in a browser or with curl. If the tunnel or host is down, you will see it there before you look at your code. A free cloudflared or ngrok URL changes every time it restarts, and the slash command keeps pointing at the old one.
Never appear "away" on Slack again
Cloud-based. No downloads. Works 24/7 even when your laptop is off.
The fix: answer first, work later
Return an empty HTTP 200 within the time budget, then post the result to the response_url that came with the command. This is the branch of our test server that did it:
import threading, time
import requests
from flask import Flask, request, make_response
app = Flask(__name__)
def later(url, delay, text):
time.sleep(delay) # the slow work goes here
r = requests.post(url, json={"response_type": "ephemeral", "text": text}, timeout=10)
print("response_url:", r.status_code, r.text)
@app.post("/slack/commands")
def commands():
form = request.form.to_dict()
threading.Thread(target=later, daemon=True,
args=(form["response_url"], 5, f"finished the slow work for '{form.get('text')}'")).start()
return make_response("", 200) # the acknowledgement Slack waits for
With a 5-second job, chat.command returned {"ok": true} in 0.6 s. Five seconds later our server printed:
response_url: 200 ok
and Slack showed "finished the slow work for 'raw ack later'" to the user. For a button click, the response_url took 5 posts and expired after 30 minutes in our interactivity tests; plan for the same limits here. In Bolt for Python the same pattern is ack() first, then respond(...). Every field of the command payload, and what each reply body shows, is in our slash command payload test.
Two more checks when the handler is fast and you still get dispatch_failed:
FAQ
Does Slack retry a failed slash command?
No. In our tests each failed command reached the server at most once. Events API deliveries are different: Slack retries those three times; see our retry timings.
What does the user see while the slow work runs?
Nothing. With the empty 200, chat.command returned {"ok": true}, the command left the message box, and no message appeared until our server posted to response_url 5 seconds later. If the work takes longer than a second or two, post a short "working on it" reply first, or return it as the body of the 200.
Stop Jiggling Your Mouse.
Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.
Related Articles
How to See All Your DMs in Slack, Including the Hidden Ones
The DMs tab lists your direct messages with people. App DMs, Slackbot and DMs with deleted accounts sit elsewhere. We compared the tab with the full list the Slack API returned.
Slack Images Not Showing? 5 Causes We Reproduced
We uploaded images to a Slack test channel and then switched each image setting off, ran /collapse, and posted from a bot that was not in the channel. Five causes, each reproduced.
How to Message Yourself on Slack (and What It Notifies)
Your own name under Direct messages opens a private DM with yourself. We sent it a note, a file, a scheduled message and a reminder, and checked which ones raised a badge.