Skip to content
HomePagesHomePages template kit

schema-invalid

"A section's schema.ts or fill-spec.ts fails a contract assertion, or cannot be loaded."

Venue: check — A section’s schema.ts or fill-spec.ts fails a contract assertion, or cannot be loaded.

A section’s schema — declared in section.ts, each slot carrying its own fill: — must:

  • parse — it satisfies SectionSchemaShape; a value that doesn’t fails here with the parse error;
  • cross-reference correctly — every reads entry names a real, author-declarable facts key, and a filled slot’s decision is one its slot type accepts;
  • satisfy the closed per-type contracts — a record item’s item_order covers every field, a select slot’s cases match its transform, a group’s members are slots that exist, an image slot’s sourceFilter and a select slot’s options.source each name a real member of their catalog, and the rest of the per-slot-type rules the schema system documents;
  • reference only facts a section is given — every ${facts.…} in a decision’s prompt strings resolves the whole way down. It names a fact the section’s slice actually carries; each further segment must be a real field of the fact above it, or a positional index into a list (${facts.tours.0.url}); and it may stop at any structure, which expands to compact JSON. So ${facts.address.citty} fails here, with the fields address does have — as does a typo one level deeper.

One violation is one diagnostic; a section with several wrong things reports all of them in the same run, not one per fix.

This is the id you also see when a section cannot be built or parsed at all — a syntax error in section.ts, a missing export, an import that doesn’t resolve. The message in that case is the underlying build error, relocated to the file it points at.

A fill decision is not free-standing — it exists to fill the slot it is declared on, and every fact it reads must be one the platform actually exposes. Declaring it on the slot settles the first half by construction: a decision’s target is the slot it rides on, so it can no longer name one that does not exist. What remains is what the declaration claims about the world. A decision that references a fact the section is not given is worse than a crash: the reference expands to nothing, the section fills, the copy reads plausibly, and the grounding you wrote the reference for is simply absent — nothing downstream can tell that from prose the model chose not to use. The same shape of silence is why a sourceFilter or an options.source outside its catalog fails here rather than at runtime: one hands the editor the wrong asset pool, the other an empty dropdown, and neither reports anything. Catching all of it at author time is the difference between a red check and a listing that publishes with a hole in it.

Read the message: it names the section, the slot in question, and what’s wrong with it.

sections/facts/section.ts
export const schema = defineSchema({
label: "Facts",
slots: {
year_built: text.short({
label: "Year built",
cap: 20,
fill: textBlock({
structure: "single_sentence",
perspective: "third",
voice: "Plain, factual.",
content: "State the year built, from ${facts.address.citty}.",
// ^ typo — `address` has no `citty`
}),
}),
},
});
Section "facts": fill-spec decision "year_built" interpolates ${facts.address.citty}, but "facts.address" has no "citty" beneath it (allowed: display, street, street_no_type, city, state, postal, unit). It would expand to nothing.
sections/facts/section.ts
year_built: text.short({
label: "Year built",
cap: 20,
fill: textBlock({
structure: "single_sentence",
perspective: "third",
voice: "Plain, factual.",
content: "State the year built, from ${facts.address.city}.",
}),
}),
  • The schema and the fill declaration — the full authoring contract for the slots and for what fills them.
  • fixtures-invalid — the sibling gate on the third contract file, fixtures.ts.
  • template-invalid — the same kind of cross-reference check, one level up, on a template composing several sections.
  • bundle-incomplete — reported instead of this id when a contract file is missing outright, rather than present and wrong.