Slack API Error Guide: 'ratelimited' HTTP 429 Too Many Requests
Fix the Slack API ratelimited / HTTP 429 error: honor Retry-After, respect per-method tiers, batch chat.postMessage, and back off correctly with curl examples.
- #slack
- #troubleshooting
- #errors
- #rate-limits
Stuck on this Slack error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
The ratelimited error (returned alongside HTTP status 429 Too Many Requests) means your app has exceeded the request budget Slack allows for a given method. Slack enforces per-method, per-workspace rate limits organized into tiers, and when you cross the threshold it rejects further calls and tells you how long to wait via the Retry-After response header. This is a throttling signal, not an error in your payload — the correct response is to back off and retry, not to change the request.
You will see the JSON body plus a 429 status and a Retry-After header:
HTTP/2 429
retry-after: 30
{
"ok": false,
"error": "ratelimited"
}
It occurs when bursty or high-frequency calls (loops over chat.postMessage, polling conversations.history, bulk users.info) outpace the method’s tier.
Symptoms
- Calls return HTTP
429witherror: ratelimited. - A
Retry-Afterheader gives the seconds to wait. - Failures cluster during bursts (startup syncs, fan-out notifications, backfills).
- Lower-tier methods (Tier 1/2) fail far sooner than Tier 4 methods.
curl -s -D - -o /dev/null -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"msg"}'
HTTP/2 429
retry-after: 30
Common Root Causes
1. Posting messages faster than ~1/second per channel
chat.postMessage is roughly Tier-limited to about one message per second per channel for sustained traffic. A tight loop blows past it.
for i in $(seq 1 20); do
curl -s -o /dev/null -w "%{http_code}\n" -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"text\":\"$i\"}"
done
200
200
429
429
The 429s start once the burst exceeds the per-channel rate.
2. Polling a Tier-3 method too aggressively
conversations.history and similar Tier-3 methods allow roughly 50+ requests/minute. Polling every second across many channels exhausts the tier.
curl -s -D - -o /dev/null \
"https://slack.com/api/conversations.history?channel=C0123456789&limit=200" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
HTTP/2 429
retry-after: 12
3. Ignoring the Retry-After header
Retrying immediately after a 429 (instead of waiting Retry-After seconds) keeps you throttled and can extend the penalty.
RESP=$(curl -s -D - -o /dev/null -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"x"}')
echo "$RESP" | grep -i retry-after
retry-after: 30
You must sleep at least 30 seconds before the next call.
4. Fan-out without batching
Sending the same message to many users via individual chat.postMessage calls multiplies requests. Slack offers no bulk-post; you must throttle yourself.
curl -s -o /dev/null -w "%{http_code} %header{retry-after}\n" \
-X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"U0AAAAAAA","text":"broadcast"}'
429 18
5. Many app instances sharing one token
Rate limits are per-method per-workspace per-token. Several pods using the same bot token share one budget, so horizontal scaling multiplies the request rate without multiplying the limit.
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": true,
"team_id": "T0AAAAAAA",
"user_id": "U0BOTBOT01"
}
All instances authenticating as the same user_id draw from the same bucket.
6. Tier-1 methods called repeatedly
Some methods are Tier 1 (about 1 request/minute). Calling them in a loop is almost guaranteed to throttle.
curl -s -D - -o /dev/null "https://slack.com/api/some.tier1.method" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
HTTP/2 429
retry-after: 47
Diagnostic Workflow
Step 1: Confirm it is a 429 with Retry-After
curl -s -D - -o /dev/null -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"probe"}'
A 429 status plus a retry-after header confirms rate limiting (versus a payload error returning 200 with ok:false).
Step 2: Identify which method is throttling
# Print status + retry-after for each method you call
curl -s -o /dev/null -w "history=%{http_code} retry=%header{retry-after}\n" \
"https://slack.com/api/conversations.history?channel=C0123456789&limit=200" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
Find the specific endpoint hitting 429; tiers differ, so the fix is method-specific.
Step 3: Honor Retry-After with a real wait
RA=$(curl -s -D - -o /dev/null -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"y"}' | awk -F': ' 'tolower($1)=="retry-after"{print $2+0}')
echo "waiting ${RA}s"; sleep "${RA:-1}"
Always sleep the advertised seconds before retrying.
Step 4: Throttle the client side
Introduce a token-bucket / fixed delay so sustained traffic stays under the method’s tier (e.g. one post per second per channel). Spread fan-out over time rather than bursting.
Step 5: Retry and confirm recovery
curl -s -o /dev/null -w "%{http_code}\n" -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"recovered"}'
200
Example Root Cause Analysis
An alerting service fans out an incident notice to 300 on-call users by looping chat.postMessage, and about a third of the deliveries fail. Capturing one failure:
curl -s -D - -o /dev/null -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"U0AAAAAAA","text":"PagerDuty incident #4821"}'
HTTP/2 429
retry-after: 22
The loop fires all 300 requests with no delay, far above the sustained per-method rate, so Slack throttles after the first burst. The code also retries failures immediately, ignoring Retry-After, which prolongs the throttle.
Fix: add a fixed delay between sends and honor Retry-After on any 429:
for u in $(cat oncall_user_ids.txt); do
code=$(curl -s -o /dev/null -w "%{http_code}" -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"$u\",\"text\":\"incident\"}")
[ "$code" = "429" ] && sleep 30
sleep 1
done
With one-second spacing and a 30-second backoff on throttle, all 300 messages deliver.
Prevention Best Practices
- Always read and obey the
Retry-Afterheader; never retry a429immediately. - Stay under each method’s tier — roughly one
chat.postMessageper second per channel — by rate-limiting on the client side. - Use exponential backoff with jitter for retries so many workers do not resynchronize and re-burst together.
- Spread fan-out and backfills over time instead of looping with no delay; Slack offers no bulk-post endpoint.
- Remember the budget is per-token per-workspace: scaling out pods on one token does not raise the limit — shard work, not the token’s quota.
- For ad-hoc triage, the free incident assistant can flag which method’s tier you are exceeding during a notification storm. See more in Slack guides.
Quick Command Reference
# Capture status + Retry-After
curl -s -D - -o /dev/null -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"probe"}'
# Status + retry-after in one line
curl -s -o /dev/null -w "%{http_code} %header{retry-after}\n" \
"https://slack.com/api/conversations.history?channel=C0123456789&limit=200" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
# Honor Retry-After then retry
RA=$(curl -s -D - -o /dev/null ... | awk -F': ' 'tolower($1)=="retry-after"{print $2+0}')
sleep "${RA:-1}"
# Confirm recovery
curl -s -o /dev/null -w "%{http_code}\n" -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"channel":"C0123456789","text":"ok"}'
Conclusion
ratelimited / HTTP 429 means you exceeded a method’s tier, and Slack is asking you to slow down. The usual root causes:
- Posting faster than about one message per second per channel.
- Polling a Tier-3 method (like
conversations.history) too aggressively. - Ignoring
Retry-Afterand retrying immediately. - Fan-out without batching or spacing the requests.
- Multiple instances sharing one token’s per-workspace budget.
- Looping a Tier-1 method limited to roughly one request per minute.
Read the Retry-After header, wait the advertised time, and throttle the client to the method’s tier — rate limits are a pacing problem, solved by backoff rather than retrying harder.
Fixed it? Get 500 Slack & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.