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
chat.postMessage rejects blocks with msg_blocks_too_long but the cumulative limit is undocumented, not validated client-side, and the error response contains no detail about what exceeded the limit or by how much. We'd love some clarity on how the limit is calculated so we can avoid it proactively.
Context
We built a CI analysis bot that posts rich_text + section + header + divider blocks via chat.postMessage (mention path). The slash command path uses respond() and works fine with identical blocks — the limit only affects chat.postMessage.
In #2509, @vegeris mentioned "12,000 text characters with a buffer for block containers." We implemented measureTextLength() that walks the block tree and sums all .text string properties. It reported 11,341 — under 12,000 — yet Slack still rejected with msg_blocks_too_long. We also note that we don't use markdown blocks (type: 'markdown'). The documented 12,000 cumulative limit on the markdown block docs applies to a block type we don't use, and there is no documented cumulative limit for rich_text, section, header, or divider blocks.
Production measurements
We instrumented every chat.postMessage call with three measurements:
blocks text — walks the blocks JSON tree and sums all .text string values, including nested text objects (e.g., HeaderBlock.text.text, SectionBlock.text.text, rich_text element .text)
blocks JSON — JSON.stringify(blocks).length
text param — length of the text argument passed to chat.postMessage
blocks text
blocks JSON
text param
blockCount
Result
4,649
7,768
2,497
28
Accepted
6,020
9,542
3,265
33
Accepted
9,597
15,561
6,463
50
Accepted
11,341
17,694
10,400
45
Rejected
We tested several ways of measuring the payload size — summing text content across blocks, JSON-serialized block size, the text parameter length, and combinations of these — but none produced a consistent threshold matching the ~13,200 figure from #2509. The tightest bound we found is blocks JSON between 15,561 (accepted) and 17,694 (rejected).
The response doesn't include a character count, limit value, or indication of what was measured — which makes it difficult to debug without trial and error.
What would help
Any of these would help developers handle this proactively:
Document the cumulative limit for non-markdown block types — the current 12,000 limit is documented only for markdown blocks. What is the limit for rich_text, section, header, and mixed-type payloads?
Clarify what is counted — text content only? serialized JSON? structural overhead? Does the text parameter count toward the limit?
Include the count and limit in the error response — e.g., "detail": "blocks content is 17,694 characters, limit is 16,000" — this alone would eliminate all guesswork
Add client-side validation in @slack/web-api that checks before sending and throws a descriptive error (related: Test utility for validating blocks #1652 has requested a block validation utility)
Export the limit as a runtime constant from @slack/web-api so developers can validate blocks before sending — per-block limits already exist in @slack/types JSDoc but the cumulative limit is absent entirely
Current workaround
We plan to catch msg_blocks_too_long, reduce the content, rebuild blocks, and retry. This should work but results in extra API calls that could be avoided with a documented limit.
chat.postMessagerejects blocks withmsg_blocks_too_longbut the cumulative limit is undocumented, not validated client-side, and the error response contains no detail about what exceeded the limit or by how much. We'd love some clarity on how the limit is calculated so we can avoid it proactively.Context
We built a CI analysis bot that posts
rich_text+section+header+dividerblocks viachat.postMessage(mention path). The slash command path usesrespond()and works fine with identical blocks — the limit only affectschat.postMessage.In #2509, @vegeris mentioned "12,000 text characters with a buffer for block containers." We implemented
measureTextLength()that walks the block tree and sums all.textstring properties. It reported 11,341 — under 12,000 — yet Slack still rejected withmsg_blocks_too_long. We also note that we don't usemarkdownblocks (type: 'markdown'). The documented 12,000 cumulative limit on the markdown block docs applies to a block type we don't use, and there is no documented cumulative limit forrich_text,section,header, ordividerblocks.Production measurements
We instrumented every
chat.postMessagecall with three measurements:blocksJSON tree and sums all.textstring values, including nested text objects (e.g.,HeaderBlock.text.text,SectionBlock.text.text, rich_text element.text)JSON.stringify(blocks).lengthtextparam — length of thetextargument passed tochat.postMessagetextparamWe tested several ways of measuring the payload size — summing text content across blocks, JSON-serialized block size, the text parameter length, and combinations of these — but none produced a consistent threshold matching the ~13,200 figure from #2509. The tightest bound we found is
blocks JSONbetween 15,561 (accepted) and 17,694 (rejected).Error response
The response doesn't help us debug:
{ "ok": false, "error": "msg_blocks_too_long", "response_metadata": { "scopes": ["chat:write", "..."], "acceptedScopes": ["chat:write"] } }The response doesn't include a character count, limit value, or indication of what was measured — which makes it difficult to debug without trial and error.
What would help
Any of these would help developers handle this proactively:
markdownblocks. What is the limit forrich_text,section,header, and mixed-type payloads?textparameter count toward the limit?"detail": "blocks content is 17,694 characters, limit is 16,000"— this alone would eliminate all guesswork@slack/web-apiso developers can validate blocks before sending — per-block limits already exist in@slack/typesJSDoc but the cumulative limit is absent entirelyCurrent workaround
We plan to catch
msg_blocks_too_long, reduce the content, rebuild blocks, and retry. This should work but results in extra API calls that could be avoided with a documented limit.