Validation
Rendering is deliberately tolerant; validation is deliberately strict. The
validators check a payload against Slack's documented acceptance rules (limits,
required fields, element placement, nesting) and throw a
BlockKitInvariantError pointing at the first violation. They run without
React, so they work in Node scripts, tests, and server code:
import { assertBlockKitData, parseBlockKitData } from "react-blockkit";
const unknownPayload: unknown = { blocks: [] };
const json = '{"blocks":[]}';
assertBlockKitData(unknownPayload, "message");
const typed = parseBlockKitData(json, "message");Functions
| Function | Signature | Use |
|---|---|---|
parseBlockKitData | (input: BlockKitInput, surface?: BlockKitSurface) => BlockKitData | Parse a JSON string or validate a block-shaped input; returns the typed payload. For unknown values, use assertBlockKitData |
assertBlockKitData | (value: unknown, surface?, path?) => asserts value is BlockKitData | Validate a full payload in place |
assertRenderableBlock | (value: unknown, surface?, path?) => asserts value is RenderableBlock | Validate a single block of any type |
assertBlockType | (value: unknown, expected: RenderableBlock["type"], surface?, path?) => void | Validate a block and require a specific type |
assertRichTextBlockData | (value: unknown, path?) => void | Validate one rich_text block |
assertTextObjectData | (value: unknown, path?, max?) => void | Validate a TextObject with an optional length limit |
assertImageElementData | (value: unknown, path?) => void | Validate an image element |
assertInteractiveElementData | (value: unknown, path?) => void | Validate an interactive element |
blocksOf | (data: BlockKitData) => readonly RenderableBlock[] | Normalize { blocks } or a bare array to the block list |
surface defaults to "message" and path to a sensible root ("data",
"block", "element", "text"). The path parameter only affects error
messages. Pass your own when validating a fragment of a larger document.
What gets checked
- Message/view block-count limits and duplicate
block_iddetection - Required fields, type discriminators, string lengths, and per-block element limits
- Legal accessory, input, and action element placement
- Rich-text nesting and preformatted/list constraints
- Table shape, cell types, row/column limits, and aggregate text budgets
- Data-table header, row width, page size, and row-header invariants
- Chart category/series/point consistency
- Card, carousel, container, task-card, and plan constraints
- Surface compatibility, listed in full below
Surface compatibility
Thirteen block types are legal on some surfaces and not others.
assertBlockKitData throws surface_mismatch when one appears on the wrong
surface:
| Legal surface | Blocks |
|---|---|
message only | card, carousel, container, context_actions, data_table, data_visualization, file, markdown, plan, table, task_card |
modal only | alert |
modal or home | input |
Every other block validates on all three surfaces. Rendering ignores surface entirely; see Rendering messages.
BlockKitInvariantError
Every validation failure throws this error class, as does the renderer's own malformed-JSON case:
import { BlockKitInvariantError, parseBlockKitData } from "react-blockkit";
const payload = { blocks: [] };
try {
parseBlockKitData(payload, "modal");
} catch (error) {
if (error instanceof BlockKitInvariantError) {
error.code; // "limit_exceeded"
error.path; // "data.blocks[2].text.text"
error.message; // "data.blocks[2].text.text: must contain at most 3000 characters"
}
}| Property | Type | Meaning |
|---|---|---|
code | BlockKitInvariantCode | Stable machine-readable failure category |
path | string | JSON path to the offending value, in Slack payload notation |
message | string | "<path>: <description>" |
Error codes
| Code | Raised when |
|---|---|
invalid_json | String input fails JSON.parse |
invalid_type | A value has the wrong JavaScript type |
missing_field | A required field is absent |
invalid_value | A value is present but illegal (empty string, bad discriminator, out-of-range number) |
limit_exceeded | A Slack length, count, or size limit is exceeded |
surface_mismatch | A block is not allowed on the validated surface |
duplicate_id | Two blocks share a block_id |
unsupported_block | A block type is not in the supported inventory |
unsupported_element | An element type is not legal in its position |