Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for Slack By James Joyner IV · · 8 min read Last reviewed Jul 2026

Slack Error Guide: 'msg_too_long' — Message Exceeds the 40k Limit

Quick answer

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
Free toolkit

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.update returns 200 with "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 text length 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.update too — 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:

  1. Dumping raw logs or stack traces into text.
  2. Large aggregate Block Kit content.
  3. Long diffs or Terraform plans posted inline.
  4. Concatenated multi-item summaries with no bound.
  5. A chat.update that 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.

Free download · 368-page PDF

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?

Free download · 368-page PDF

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.