Slack Error Guide: 'msg_too_long' — Message Exceeds the 40k Limit
Fix the Slack msg_too_long error: stay under the ~40,000-character message limit by truncating, threading, or attaching logs as a file snippet, with real curl examples and safe chunking.
- #slack
- #api
- #troubleshooting
- #errors
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 msg_too_long error means the message body you sent to chat.postMessage, chat.update, or chat.scheduleMessage is over Slack’s maximum length. A single message tops out around 40,000 characters, and Slack strongly recommends staying well under that (roughly 4,000 characters per message renders best). The most common trigger in ops tooling is dumping raw output — a stack trace, kubectl describe, a Terraform plan, a CI log — straight into the text field. This is a size problem in your payload: the token and channel are fine, but the content must be shortened, split, or moved into a file before Slack will accept it.
The response is HTTP 200 with ok: false:
{
"ok": false,
"error": "msg_too_long"
}
It shows up whenever a message assembles unbounded content — logs, diffs, lists — without a length guard.
Symptoms
chat.postMessage/chat.updatereturns200with"error": "msg_too_long".- Failures correlate with big payloads (verbose failures, long diffs) and pass for small ones.
- A notifier that works in normal runs fails specifically on the noisiest incidents — exactly when you need it.
- Splitting the same content into shorter messages succeeds.
BIG=$(head -c 45000 < /dev/zero | tr '\0' 'x')
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"text\":\"$BIG\"}"
{
"ok": false,
"error": "msg_too_long"
}
Common Root Causes
1. Dumping raw logs into text
The classic cause: piping an entire log or stack trace into text.
LOG=$(head -c 50000 < /dev/urandom | base64 | tr -d '\n')
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"text\":\"$LOG\"}"
{"ok":false,"error":"msg_too_long"}
2. Large Block Kit text pushing total size over the limit
Even split across blocks, the combined payload can exceed the message limit (each section text is separately capped at 3000, which surfaces as invalid_blocks, but the aggregate size can trip msg_too_long).
python3 - <<'PY'
import json
text = "line\n"*12000 # ~60k chars
print("chars:", len(text))
PY
chars: 60000
3. Long diffs or plans posted inline
A Terraform plan or a Git diff can easily run past 40k characters on a big change.
wc -c terraform-plan.txt
73412 terraform-plan.txt
Posting that file’s contents as text fails.
4. Concatenated multi-item summaries
Looping over hundreds of items and appending each to one growing string overflows without any single item looking large.
python3 -c 'print(len("service ok\n"*4000))'
44000
5. chat.update growing an already-large message
Appending to a live status message over time can push a message that started fine over the limit on a later update.
curl -s -X POST https://slack.com/api/chat.update \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"ts\":\"1720000000.000100\",\"text\":\"$(head -c 45000 </dev/zero|tr '\0' 'x')\"}"
{"ok":false,"error":"msg_too_long"}
Diagnostic Workflow
Step 1: Measure the payload before sending
Count the characters of the text (or serialized blocks) so you know how far over you are:
python3 -c 'import json;p=json.load(open("payload.json"));print("text chars:", len(p.get("text","")))'
text chars: 51280
Anything above ~40,000 will be rejected; aim for well under 4,000 for readability.
Step 2: Confirm it is length, not blocks
If you use blocks, a per-block over-length shows as invalid_blocks; a whole-message over-length shows as msg_too_long. Check which:
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d @payload.json | python3 -c 'import sys,json;print(json.load(sys.stdin)["error"])'
msg_too_long
Step 3: Truncate with a pointer to the full content
Send a bounded head/tail and link out to the full log:
HEAD=$(head -c 3000 build.log)
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"text\":\"Build failed. First 3k of log:\n\`\`\`$HEAD\`\`\`\nFull log: https://ci.example.com/run/4821\"}"
{"ok":true,"ts":"1720000000.000300"}
Step 4: Attach the full log as a file instead of inline text
For the complete content, upload it as a snippet with the files upload flow rather than cramming it into a message:
# Step 1: get an upload URL
curl -s -X POST "https://slack.com/api/files.getUploadURLExternal" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
--data-urlencode "filename=build.log" \
--data-urlencode "length=$(wc -c < build.log)"
{"ok":true,"upload_url":"https://files.slack.com/upload/v1/REDACTED","file_id":"F0LOG123"}
Then POST the bytes to upload_url and call files.completeUploadExternal with the channel_id to share it — the channel gets a readable, searchable file instead of a rejected message.
Step 5: Chunk long lists into multiple threaded messages
Split a long summary into ≤3,500-char parts and thread them under a header:
python3 - <<'PY'
text = open("summary.txt").read()
parts = [text[i:i+3500] for i in range(0, len(text), 3500)]
print("parts:", len(parts))
PY
parts: 13
Post the first as the parent, then the rest with thread_ts set to the parent’s ts.
Example Root Cause Analysis
An incident bot posts the failing pod’s kubectl describe output to the incident channel. On a crash-looping pod with a huge event history, it fails:
kubectl describe pod api-7f9c > describe.txt
wc -c describe.txt
61240 describe.txt
The bot piped the entire 61k-character describe into text, so Slack returned msg_too_long and responders saw no context at all — the worst time to drop a message. The fix is to post a short, high-signal summary inline and attach the full output as a file:
SUMMARY=$(grep -E 'Reason:|Message:|Last State|Restart Count' describe.txt | head -c 2500)
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0INCIDENT1\",\"text\":\"api-7f9c crashloop — key events:\n\`\`\`$SUMMARY\`\`\`\nFull describe attached.\"}"
{"ok":true,"ts":"1720000000.000400"}
Posting a trimmed summary plus the full describe as an attached file keeps the message small, always delivers, and still gives responders the complete data one click away.
Prevention Best Practices
- Cap
textlength in code (truncate to a few thousand chars) before every send; never post unbounded output. - Post a short summary inline and link out to the full log/run URL instead of pasting entire logs.
- Attach large content as a file via the external upload flow (
files.getUploadURLExternal→ upload →files.completeUploadExternal) so the channel stays readable and searchable. - For long lists, chunk into ≤3,500-char messages and thread them under a header rather than one giant post.
- Guard
chat.updatetoo — a message that grows over time can cross the limit on a later update. - Aim for well under 4,000 characters per message for readability, not just under the hard ~40,000 ceiling.
- For quick triage of a rejected notification, the free incident assistant can suggest what to trim or attach. See more in Slack guides.
Quick Command Reference
# Measure text length before sending
python3 -c 'import json;print(len(json.load(open("payload.json")).get("text","")))'
# Confirm the error is length (not blocks)
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d @payload.json | python3 -c 'import sys,json;print(json.load(sys.stdin)["error"])'
# Truncate + link out
HEAD=$(head -c 3000 build.log)
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" -H "Content-Type: application/json" \
-d "{\"channel\":\"C0123456789\",\"text\":\"\`\`\`$HEAD\`\`\`\nFull: https://ci.example.com/run/4821\"}"
# Start a file upload for the full log
curl -s -X POST "https://slack.com/api/files.getUploadURLExternal" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
--data-urlencode "filename=build.log" \
--data-urlencode "length=$(wc -c < build.log)"
Conclusion
msg_too_long means your message body is over Slack’s ~40,000-character ceiling — a size problem, solved by shrinking or relocating the content, not by retrying. The usual root causes:
- Dumping raw logs or stack traces into
text. - Large aggregate Block Kit content.
- Long diffs or Terraform plans posted inline.
- Concatenated multi-item summaries with no bound.
- A
chat.updatethat grows a message past the limit.
Measure the payload, post a short summary with a link, attach the full content as a file, or thread it in ≤3,500-char chunks. Keep messages well under 4,000 characters and your notifications stay both deliverable and readable — especially during the noisy incidents when they matter most.
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.