Validation

Rendering is deliberately tolerant; validation is deliberately strict. The validators check a payload against the package's strict contract (limits, required fields, element placement, nesting, and surface rules) 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

FunctionSignatureUse
parseBlockKitData(input: BlockKitInput, surface?: BlockKitSurface) => BlockKitDataParse 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 BlockKitDataValidate a full payload in place
assertRenderableBlock(value: unknown, surface?, path?) => asserts value is RenderableBlockValidate a single block of any type
assertBlockType(value: unknown, expected: RenderableBlock["type"], surface?, path?) => voidValidate a block and require a specific type
assertRichTextBlockData(value: unknown, path?) => voidValidate one rich_text block
assertTextObjectData(value: unknown, path?, max?) => voidValidate a TextObject with an optional length limit
assertImageElementData(value: unknown, path?) => voidValidate an image element
assertInteractiveElementData(value: unknown, path?) => voidValidate 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 sets both error.path and the "<path>:" prefix in error.message. Pass your own when validating a fragment of a larger document. This function argument is separate from <BlockKit surface>: rendering with that prop never invokes a validator.

What gets checked

  • Message/view block-count limits and duplicate block_id detection
  • 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
  • The validator's surface rules, listed in full below

Validator surface rules

The validator applies surface restrictions to thirteen block types and throws surface_mismatch when one appears outside the listed surface:

Validator accepts onBlocks
message onlycard, carousel, container, context_actions, data_table, data_visualization, file, markdown, plan, table, task_card
modal onlyalert
modal or homeinput

Known compatibility limitation: Slack and the renderer support input blocks in messages, but the current validator rejects that combination with surface_mismatch. Do not treat that rejection as evidence that Slack rejects the payload. Every other block validates on all three surfaces. Rendering only records the selected surface; see Rendering messages.

BlockKitInvariantError

Every validation failure throws this error class, as does the renderer's own malformed-JSON case:

import { isBlockKitInvariantError, parseBlockKitData } from "react-blockkit";

const payload = {
  blocks: [
    { type: "divider", block_id: "same" },
    { type: "divider", block_id: "same" },
  ],
} as const;

try {
  parseBlockKitData(payload, "message");
} catch (error) {
  if (isBlockKitInvariantError(error)) {
    error.code; // "duplicate_id"
    error.path; // "data.blocks[1].block_id"
    error.message; // 'data.blocks[1].block_id: "same" is already used in this payload'
  }
}

Prefer isBlockKitInvariantError(error) to instanceof. The package publishes separate ESM and CommonJS class copies, so instanceof can be false when an error crosses that build boundary. The exported guard recognizes either copy.

PropertyTypeMeaning
codeBlockKitInvariantCodeStable machine-readable failure category
pathstringJSON path to the offending value, in Slack payload notation
messagestring"<path>: <description>"

Error codes

CodeRaised when
invalid_jsonString input fails JSON.parse
invalid_typeA value has the wrong JavaScript type
missing_fieldA required field is absent
invalid_valueA value is present but illegal (empty string, bad discriminator, out-of-range number)
limit_exceededA Slack length, count, or size limit is exceeded
surface_mismatchA block is not allowed on the validated surface
duplicate_idTwo blocks share a block_id
unsupported_blockA block type is not in the supported inventory
unsupported_elementAn element type is not legal in its position