template-kit/section-unrenderable
The template-kit/section-unrenderable authoring rule — what it enforces, why, and how to fix it.
A section that never rendered has not passed the render checks — it has skipped them. This rule is what stops “skipped” from reading as “clean”.
Every section must load and build its fixture set, so that at least one fixture actually
server-renders. If loading the section, parsing its fixtures.ts, or building the fixture
corpus throws, the section fails this rule.
You will usually see a second, more specific id alongside it — schema-invalid,
fixtures-invalid or bundle-incomplete — naming the underlying fault. That one tells
you what to fix. This one tells you what was not checked as a result: the section’s
slot, row and group marker coverage, its render determinism, and its render invariants
were all skipped, because none of them can be evaluated without rendered output.
Reason
Section titled “Reason”Every other check in this stage is a statement about rendered DOM: this slot’s marker reached the page, this row carries its index, this group’s members are inside it. Each one is evaluated by looking at output — and a section that produced no output trivially satisfies all of them.
That makes a broken section indistinguishable from a perfect one at exactly the moment you
most need to tell them apart. A section whose fixtures.ts stopped parsing keeps
reporting clean marker coverage for as long as it stays broken, and the marker defects
that accumulate underneath surface only once someone repairs the fixtures — usually far
from the change that introduced them.
Fix the error in the message, then re-run. There is nothing to configure and no way to opt out: coverage cannot be proven without a render.
The most common cause is a module-scope side effect in one of the section’s four contract files, which runs at load time rather than render time.
Before
Section titled “Before”schema.ts reads an environment value while the module is evaluating, so loading the
section throws before any fixture can be built:
// sections/hero/schema.ts — template-kit/section-unrenderableimport type { SectionSchemaShape } from "@homepages/template-kit";
// Throws at import time when the variable is unset — which it is under `check`.const BRAND = process.env.BRAND_NAME!.toUpperCase();
export const schema = { meta: { displayName: `${BRAND} Hero` }, slots: { headline: { type: "text", size: "medium", required: true, editable_by_user: true }, },} as const satisfies SectionSchemaShape;The schema is static, so the module loads and every fixture renders:
// sections/hero/schema.ts — template-kit/section-unrenderableimport type { SectionSchemaShape } from "@homepages/template-kit";
export const schema = { meta: { displayName: "Hero" }, slots: { headline: { type: "text", size: "medium", required: true, editable_by_user: true }, },} as const satisfies SectionSchemaShape;Anything that varies per deliverable belongs in a slot the editor fills, not in a value read while the module loads.