Skip to content
HomePagesHomePages template kit

fixtures-invalid

"A section's fixtures.ts does not satisfy the fixture-module shape."

Venue: check — A section’s fixtures.ts does not satisfy the fixture-module shape.

fixtures.ts must export a named fixtures built from defineFixtures — the value that call returns, exported as-is:

export const fixtures = defineFixtures(schema, (scenario) => ({ base: scenario("luxuryMultiUnit", { … }) }));

That value is branded, and the check verifies both halves of the claim: that the export carries the brand at all, and that what it carries is well-formed. The two failures read differently, on purpose.

Exporting a plain object — most often a hand-written { base: { slots: … } } shape — fails the first check, and the message names the call to reach for:

Section "hero": fixtures.ts must export `fixtures` from a `defineFixtures(schema, …)` call. The hand-authored `{ base: { slots: … } }` shape isn't a valid module — build the module from a scenario instead: `defineFixtures(schema, (scenario) => ({ base: scenario(…) }))`.

A branded module that is internally malformed fails the second, and each violation names the exact path inside the module ("base", "base.slots", "states.empty-address", …) and the shape expected there. In practice you reach this only by hand-writing the resolved shape rather than calling defineFixtures.

A scenario that cannot supply a fact one of your slots needs is not this rule: that failure throws while fixtures.ts loads, so it surfaces as section-unrenderable, naming the scenario, the fact, and the slot.

The schema and the fill spec are both Zod-parsed on the way into every other check, so a malformed one is caught immediately. fixtures.ts is the exception: nothing else parses it, so without this gate a wrong shape would surface only once the render stage read it directly — a raw crash mid-render, blamed on whatever line happened to dereference the missing field, never on the fixture that was actually wrong.

This gate exists to move that failure to where the mistake was made, with a message about the fixture module instead of a stack trace from three files away.

Build the module with defineFixtures rather than writing its shape by hand. Everything a hand-written shape would spell out — resolving each fact-bound slot, defaulting each variant axis, tagging where every value came from — is what that call does for you.

sections/hero/fixtures.ts
export const fixtures = {
base: {
slots: { headline: "A mansard Victorian in the heart of Jamaica Plain" },
},
states: {
// A plain object skips defineFixtures entirely — no brand, no resolution.
"long-headline": {
slots: {
headline:
"A mansard Victorian with a terrazzo lobby, quartz kitchens throughout, and a top-floor penthouse",
},
},
},
};
sections/hero/fixtures.ts
export const fixtures = defineFixtures(
schema,
(scenario) => ({
base: scenario("luxuryMultiUnit", {
headline: "A mansard Victorian in the heart of Jamaica Plain",
}),
states: {
// A state is COMPLETE, not a diff against base: it resolves from its own
// `scenario()` call, so restate every authored slot it needs. Here that is
// just `headline` — every fact-bound slot resolves on its own.
"long-headline": scenario("luxuryMultiUnit", {
headline:
"A mansard Victorian with a terrazzo lobby, quartz kitchens throughout, and a top-floor penthouse",
}),
},
}),
);
  • fixtures.ts — the fixtures declaration in full.
  • schema-invalid — the sibling gate on the schema and fill spec, both in section.ts.
  • bundle-incomplete — reported instead of this id when fixtures.ts is missing outright, rather than present and wrong.