Diagnostics
Generated from diagnosticDefinitions in packages/core/src/diagnostics.ts — 44 codes (29 error, 6 warn, 8 lint, 1 notice). Do not edit by hand.
Every diagnostic Kovo emits has a stable KV### code. The compiler, the CLI, and vp check all draw their messages from the one registry below, so the code you see in your terminal is the code you look up here. Each entry lists what triggered it and the fix.
Error#
Build-blocking. vp check fails until you resolve it.
| Code | Message | Fix |
|---|---|---|
KV201 |
Closure captures unserializable value. | Fixes: move the value into component/query state via ctx; pass serializable element params with data-p-; or keep shared constants in module scope. Handlers may reference only state/ctx/event, data-p- element params, named imports, and statically serializable module constants. Blocked reason: captured runtime values cannot be serialized into the generated handler module boundary. SPEC §4.3 and §5.2 require handler lowering to cross only explicit serializable capture channels. |
KV220 |
Literal href or form action matches no declared route. | Would lower to: a route-checked href/action that participates in the typed route registry. Blocked reason: the literal target does not match any declared canonical route path. Fixes: use a typed route helper, declare the route, correct the literal path, or mark an intentional full-origin/external navigation with the external escape hatch. SPEC §6.4 and §9.5 require navigation targets to stay type-checked against the route table. Escape: external/full-origin URLs opt out because they are outside the app route graph. |
KV221 |
IDREF references an id not present in component scope. | Would lower to: light-DOM IDREF wiring whose target id exists in the same component scope. Blocked reason: the referenced id is absent, outside the validated scope, or hidden behind a different component boundary. Fixes: add the target id in this component scope, pass a generated id through props, or correct the IDREF attribute value. SPEC §4.5 and §6.4 require IDREFs such as commandfor, popovertarget, for, and aria-* to resolve at compile time. |
KV222 |
Hand-written binding stamp disagrees with the typed expression it wraps. | Would lower to: the compiler-derived data-bind stamp for the typed JSX expression. Blocked reason: a hand-written stamp names a different path than the expression it wraps, so server render and client update semantics could drift. Fixes: remove the hand-written stamp and let the compiler derive it, or make the stamp path exactly match the typed expression. SPEC §4.8 treats typed expressions and binding stamps as one fact and rejects drift. |
KV224 |
Static id is duplicated in component scope or appears inside a repeatable stamp. | Blocked reason: duplicate static ids make IDREF proofs ambiguous, and static ids inside repeatable stamps can produce multiple elements with the same id. Fixes: generate ids from props/kovo-key, move the id outside the repeatable subtree, or pass a unique id down to the component. SPEC §4.5 requires ids to be unique by construction so KV221 IDREF validation remains meaningful. |
KV225 |
JSX nesting violates the HTML content model. | Would lower to: HTML whose parsed DOM preserves the authored JSX tree. Blocked reason: the HTML parser would re-parent or drop invalid children, changing morph identity and fragment targets after serving. Fixes: use content-model-valid wrapper elements, move table rows into table/section parents, or split paragraph/block content into valid siblings. SPEC §4.2 requires compiler-served HTML and parsed DOM shape to agree. |
KV226 |
kovo-deps or kovo-c names an unknown query instance or component. | Would lower to: emitted IR stamps whose kovo-c and kovo-deps names resolve to known components and query instances. Blocked reason: residual compiler stamps reference a component or query that is not present in the module/registry facts. Fixes: recompile from TSX source, correct the generated stamp, or add the missing component/query fact to the compile graph. SPEC §5.2 allows lowered IR only as compiler output/fixpoint input, and fixpoint validation must reject stale names. |
KV227 |
Binding path traverses a nullable segment without ?. | Blocked reason: the binding path crosses a nullable query segment without declaring empty-on-null behavior. Fixes: write the nullable traversal with ?., extract a named derive that handles null explicitly, or make the projection non-null in the query. SPEC §4.8 requires empty-on-null semantics to be explicit so the server renderer and loader cannot drift. |
KV228 |
Ambiguous route table: two routes can match the same canonical request path or duplicate route path. | Blocked reason: static-first route matching cannot choose a single canonical handler for at least one request path. Fixes: remove duplicate route facts, split overlapping patterns, add a static segment, or make one route path more specific. SPEC §9.5 requires route matching to be unambiguous at compile time. |
KV230 |
Fragment-target children cannot lower to a component reference. | Blocked reason: fragment responses must fully describe the DOM they produce, but these children cannot be hoisted through serializable props. Fixes: pass serializable props, move browser/request/db values behind a server fragment, or render children inside the fragment target itself. SPEC §4.5 requires fragment-target children to lower to component references when they cross the target boundary. |
KV231 |
Unmergeable attribute conflict in primitive composition. | Would lower to: a single composed attribute set for primitive composition. Blocked reason: both primitive and author write an attribute whose merge rule is ambiguous or unsafe, such as IDREF, data-p-*, kovo-c, or kovo-state. Fixes: keep one writer, pass the value through the primitive API, or move the relationship/state ownership to one component. SPEC §4.6 defines primitive attribute merge rules and treats double-wired relationships as errors. |
KV233 |
Two writers target the same binding slot. | Would lower to: exactly one writer for each data-bind target slot. Blocked reason: multiple bindings target the same text/attribute slot, so the client loader cannot choose a single update source. Fixes: keep one binding, split values across distinct elements/attributes, or combine the values in a named derive before binding. SPEC §4.6 and §4.8 require binding slots to have a single writer. |
KV234 |
Package component prefix registration conflict or reservation violation. | Would lower to: package-scoped component names, CSS scopes, and behavior attributes using one effective prefix. Blocked reason: the prefix is missing, invalid, duplicated, or reserves kovo-* outside @kovojs/* packages. Fixes: assign a lowercase dash-terminated unique prefix, alias one package, or use kovo-* only for framework packages. SPEC §6.1.1 requires app-wide unique package component prefixes. |
KV235 |
App source hand-authors lowered IR/string-rendered components; write TSX and let the compiler emit IR. | Blocked reason: app source is hand-authoring lowered string/render IR instead of TSX. Fixes: write JSX with typed expressions and let the compiler emit renderSource(), kovo-c, kovo-deps, and data-bind. SPEC §5.2: TSX is the sole app-authoring surface. Escape: there is no v1 suppression or ejection workflow for hand-authored lowered IR. |
KV236 |
Unsafe output context requires an explicit trusted Kovo escape hatch. | Blocked reason: the output context can execute script, navigate unexpectedly, inject unsafe CSS, or bypass normal JSX escaping. Fixes: route URLs through typed route helpers; mark intentional external links with external; keep dynamic styling to compiler-generated safe properties; or pass raw HTML only as a Kovo TrustedHtml value. SPEC §1 and §5.2 require compiler output to be auditable; unsafe output contexts cannot depend on implicit browser or runtime sanitization. |
KV237 |
Duplicate component effective wire name. | Would lower to: one derived component registry key per component across the app graph. Blocked reason: duplicate derived registry keys make component identity, CSS scoping, fragment routing, and graph facts ambiguous. Fixes: rename the exported component binding, or move one component so its derived module path namespace differs. SPEC §4.2 and §4.8 make derived component names load-bearing for identity, scoped CSS, fragments, and graph facts; duplicate registry keys are ambiguous. |
KV238 |
Duplicate fragment-target wire name. | Would lower to: one derived fragment-target registry key that maps to exactly one component render entry. Blocked reason: duplicate fragment-target wire names make enhanced fragment patch routing ambiguous. Fixes: rename the exported component binding, add stable authored key identity for repeated instances, move one component so its derived module path namespace differs, or set disableServerRefresh: true on the query-backed component that should not receive enhanced patches. SPEC §4.5, §4.8, and §6.2 make fragment-target names derived registry-visible identities; duplicate keys make enhanced fragment patches ambiguous. |
KV239 |
Duplicate static view-transition name. | Would lower to: static view-transition-name values that uniquely pair old and new DOM elements. Blocked reason: duplicate static transition names leave the browser and compiler without one canonical element pair. Fixes: give one static viewTransitionName a distinct value, or make the transition name dynamic only when page composition proves uniqueness. SPEC §8 uses view-transition-name as a cross-document element-pair identity; duplicate static names in one rendered module or supplied registry facts are ambiguous. |
KV240 |
Duplicate query-shape fact for one query name. | Would lower to: one query-shape fact per query name for server render, client updates, and binding validation. Blocked reason: duplicate query-shape facts would make graph indexing silently choose one shape for all generated bindings. Fixes: emit exactly one query-shape fact per query name, or rename one query so generated binding metadata has a single source of truth. SPEC §4.8 query binding validation depends on one stable shape per query; duplicate facts would otherwise silently last-write-wins during graph indexing. |
KV242 |
Enhanced mutation form fields do not match mutation input schema. | Would lower to: an enhanced mutation form whose successful control names exactly match the bound mutation input schema. Blocked reason: form field names are part of the mutation input contract; unknown or missing names would only fail after submit. Fixes: rename the control, add the missing required control, or change the mutation input schema so the field set matches the form. SPEC §6.2 and §6.3 require form control names to be statically checked against the bound mutation input schema. |
KV302 |
data-bind path is not present in the declared query shape. | Would lower to: a data-bind path that the server renderer and loader can both read from the declared query/state shape. Blocked reason: the path is absent from the declared shape, so a server render or client update would read undefined. Fixes: correct the binding path, update the query projection/schema, or extract a named derive with declared inputs. SPEC §4.8 and §6.2 require bindings to type-check against query shapes. |
KV303 |
Fragment target render input is not declared as query data or stamped props. | Would lower to: a fragment target that can be re-rendered from declared query data plus stamped props. Blocked reason: the render input is outside those channels, so a fragment response could not reconstruct the subtree. Fixes: declare the value as query data, stamp it as a serializable prop, or move the dependency inside the fragment target. SPEC §4.5 requires fragment targets to be reconstructible from declared server inputs. |
KV304 |
Reserved query name is not allowed. | Blocked reason: the query name collides with a reserved binding root such as state. Fixes: rename the query instance to an app-owned root and update its bindings. SPEC §4.8 reserves binding roots so query paths and island-local state paths stay unambiguous. |
KV402 |
Write touched an undeclared domain. | See message. |
KV404 |
Write to unmapped table. | See message. |
KV407 |
Query read from undeclared domain. | No mutation touch graph writes that domain. |
KV408 |
Declared row key differs from observed row predicate. | See message. |
KV410 |
Query result shape failed declared output schema. | Opaque query projection requires a declared output schema. |
KV411 |
Query read set includes an exempt table. | See message. |
Warn#
Non-blocking warning. The check passes, but the framework wants your attention.
| Code | Message | Fix |
|---|---|---|
KV241 |
Derived component registry key changed since the previous emitted graph. | Blocked reason: derived component registry keys are deploy-load-bearing; changing one can strand in-flight documents whose morph identity still names the prior emitted component. Fixes: keep the component binding and module path stable across deploys, or review the rename/move as an intentional identity migration and refresh the previous registry facts. SPEC §4.2 and §4.8 make derived component names load-bearing for kovo-c identity, scoped CSS, fragments, and graph facts. |
KV310 |
Invalidated query lacks optimistic transform. | Would lower to: an optimistic status for each invalidated query edge, such as a transform or await-fragment decision. Blocked reason: a mutation invalidates a query without declaring how the UI should predict or defer that update. Fixes: add an optimistic transform, declare await-fragment, or narrow the invalidation so the query is not touched. SPEC §11.4 requires mutation writes, query invalidations, and optimistic coverage to be checked edge by edge. |
KV311 |
Query/state-dependent DOM position has no update status. | Would lower to: a data-bind/update plan, fragment boundary, isomorphic component, or renderOnce marker for the rendered position. Blocked reason: the compiler found a query/state-dependent DOM position without an update strategy. Fixes: add a data-bind/query update plan, mark the expression renderOnce, move the subtree behind a fragment target, or make the component isomorphic. SPEC §4.9 requires every query/state-dependent rendered position to have plan, fragment, isomorphic, or renderOnce coverage. |
KV403 |
Declared domain was never observed written. | See message. |
KV405 |
Conditional write branch was never executed under instrumentation. | See message. |
KV406 |
Statically un-analyzable write site; manual touches required. | See message. |
Lint#
Style/clarity guidance. Surfaced by vp check; non-blocking by default.
| Code | Message | Fix |
|---|---|---|
KV210 |
Anonymous handler; name it for stable identity. | Would lower to: a generated Component$element_event handler export with a stable source-derived URL. Blocked reason: anonymous handler identity is less stable for generated artifacts, explanations, and agent repairs. Fixes: extract a named function in module scope or reference a named local handler from the JSX event. SPEC §5.2 requires readable, source-derived emitted names; this lint is advisory and has no suppression beyond accepting the generated fallback name. |
KV211 |
on:load eager trigger requires a justification comment. | Blocked reason: on:load runs at parse time and adds eager JavaScript to the page budget. Fixes: use a user/event trigger instead, or attach an adjacent KV211 justification comment when parse-time execution is intentional. SPEC §4.7 keeps on:load grep-visible as the eager-JS escape hatch. Escape: an attached KV211 justification comment preserves the lint trail without blocking compilation. |
KV212 |
Unknown on:* event or execution trigger name. | Blocked reason: unknown on:* triggers cannot be mapped to the closed event/trigger vocabulary the loader understands. Fixes: use a DOM event name, use one of Kovo's declared execution triggers, or move the behavior into a component primitive that owns the attribute. SPEC §4.7 requires declared execution so generated artifacts remain auditable. |
KV223 |
Redundant hand-written binding stamp in sugar; the compiler derives it. | Would lower to: the same data-bind stamp the author already wrote by hand. Blocked reason: the stamp is redundant in app-authored TSX because the compiler can derive it from the typed expression. Fixes: remove the hand-written data-bind stamp and keep the typed JSX expression as the source of truth. SPEC §4.8 permits residual stamps for emitted IR fixpoint validation, but app TSX should not hand-author derivable stamps. Escape: emitted compiler artifacts may retain residual stamps for fixpoint checks; app source should use TSX sugar. |
KV232 |
Author overrides a primitive-owned ARIA or state attribute. | Would lower to: author-visible override of a primitive-owned ARIA, role, or state attribute. Blocked reason: the override is allowed but can change accessibility semantics or be clobbered by runtime-updated primitive state. Fixes: prefer the primitive API, remove the override, or keep it intentionally and audit the generated merge explanation. SPEC §4.6 keeps this override as a lint-level escape hatch so author intent stays visible. Escape: compilation continues; the lint documents the override for review. |
KV301 |
Server fact stored in island-local state. | Blocked reason: server/query facts stored in island-local state create a second client-owned copy of server truth. Fixes: keep the value in query data, derive UI-only state from client intent, or store only local presentation state. SPEC §4.1 keeps query data server-owned and local state private/client-owned. |
KV320 |
Event payload overlaps query data; use a transform. | Blocked reason: a fire-and-forget event payload is carrying data that overlaps server-owned query facts. Fixes: send only client intent, use an optimistic transform for query data, or route the change through a mutation/domain write. SPEC §6.4 keeps cross-island events for intent, not as a shadow transport for server facts. |
KV330 |
Direct db access in a mutation handler; route through domain. | Blocked reason: direct request/db access in a mutation handler bypasses the domain write surface and weakens touch-graph analysis. Fixes: move writes behind a domain() module, inject the domain operation into the handler, or use the typed transaction context only inside the domain layer. SPEC §11.4 and §14 require writes to flow through domains so invalidation and verifier diagnostics stay complete. |
Notice#
Informational. The framework degraded behavior and is telling you how.
| Code | Message | Fix |
|---|---|---|
KV409 |
Non-eq predicate degraded to table-level invalidation. | See message. |