Error Codes
Reference for all WF-* error codes. Click a category button below to filter.
Showing:
WF-001
Root element not found
Framework initialization cannot find the specified root DOM element. Check that your mount target exists in the HTML before calling wildflower.start().
WF-002
Invalid configuration value
A configuration attribute carries a value the framework does not recognize, so the default is used instead. The warning gives the attribute and the accepted values (for example data-error-handling accepts log, throw, or silent). The Attribute Reference lists every accepted value. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-003
Capability excluded from this build tier
A definition or markup uses a capability this build tier excludes, so it silently does nothing: tick() defined in a build without the frame loop (pool module excluded), or scoped-slot read bindings in the nano tier. Switch to a build that includes the capability, or remove the usage. The warning identifies the specific capability and the tier boundary. The Distribution Bundles table maps capabilities to tiers. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-101
Error initializing component
A component's init() method or setup logic threw an exception. Check the browser console for the underlying error. The Error Boundaries page covers onError and the handling chain.
WF-102
Component instance not found
Attempting to access a component that doesn't exist in the registry. Verify the component name matches its data-component attribute and that it has been registered. The Components page covers registration and matching.
WF-103
Component context not available
A component's context object is missing when required. This usually indicates the component was destroyed or not fully initialized.
WF-104
Error in parent event handler
A parent component's event handler threw an exception when invoked by a child. Check the parent's method for errors.
WF-105
Manual DOM write on an engine-owned node
A component called .text() on a data-bind node, .html() on a data-bind-html or data-list node, or .remove() on a managed node through the $el() helper. The engine keeps those nodes current, so the manual write will be overwritten by the next update or leave the engine tracking a removed node. Update state instead and let the binding do the writing. Unmanaged nodes stay free, and .val() on a data-model input is the sanctioned bridge. The DOM Helpers page draws the whole boundary. Warning severity (console.warn, never throws); fires when debug mode is on (the default in development builds).
WF-106
destroy() with the element still in the document
destroyComponent() ran while the component's element was still connected, so the next scan will auto-resurrect it as a fresh instance with init() re-fired. For a real teardown remove the element as well (instance.element.remove()); if you wanted a reset, re-initialize state instead. Removing the element without calling destroy is always safe: the engine garbage-collects instances whose elements leave the document. The destroyComponent section shows the correct pair. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-107
Declared provider never provided
A definition lists a key in uses: that nothing ever registered, so the $name accessor is never attached and reads of it are undefined. Register the provider with wildflower.provide('name', value) before components that use it initialize, or fix the key if it is a typo. The Service Providers section shows the registration. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-108
Directive or plugin registration overwritten
A directive or plugin was registered under a name that already exists, and the new registration replaced the original. If both registrations are intentional (hot reload, deliberate override) the warning can be ignored; otherwise rename one. Note the asymmetry with components and stores, where a conflicting re-registration keeps the original instead (WF-215). The Plugins page covers directive registration. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-201
Error evaluating computed property
A computed property function threw an exception during evaluation. Check that all referenced state properties exist and have expected types. The Computed Properties page covers the evaluation contract.
WF-202
Circular dependency detected
Two or more computed properties reference each other, creating an infinite loop. Restructure your computed properties to break the cycle. The Avoiding Circular Dependencies section shows the restructure.
WF-203
Error setting state value
The reactive proxy's set trap encountered an error. This can happen when assigning invalid values or when the state object has been corrupted.
WF-204
Error deleting state value
The reactive proxy's delete trap encountered an error when removing a state property.
WF-205
Error loading state from storage
Failed to read persisted state from localStorage or sessionStorage. The stored data may be corrupted or the storage quota exceeded. The Built-in Persistence section covers storageKey and autoSave.
WF-206
Error saving state to storage
Failed to persist state to localStorage or sessionStorage. Check that the storage quota has not been exceeded and that the data is serializable. The Built-in Persistence section covers the surface.
WF-207
Invalid parameter for state update
A state update method received an argument of the wrong type. Verify you're passing the correct data type.
WF-208
Computed property does not exist
Retired in v1.3. This code was reserved for reads of undefined computed properties but never fired from any code path. Misspelled computed and state references are caught by binding validation in development builds, which warns with a did-you-mean at bind time. The code number is not reused.
WF-209
Computed property must be a function
A computed property was defined as a value instead of a function. Computed properties must be functions that return a value. The Computed Properties page shows the function form.
WF-210
Invalid path segment
A dotted path like user.profile.name contains an invalid segment. Check for typos or undefined intermediate objects.
WF-211
Error in subscription callback
A user-provided subscription callback threw an exception. Check the function passed to subscribe(). The Communication page covers subscriptions.
WF-212
Pool aggregate read inside a computed
Retired in v1.3. Pool aggregates (pool.length, pool.size) are reactive on demand as of v1.3: a computed reading them re-evaluates when entities are added, removed, or cleared, so the trap this warning guarded no longer exists and the warning was removed. On v1.2 and earlier, aggregates bypass reactivity and a computed reading them evaluates once and goes silently stale; the workaround there is mirroring the count into reactive state inside a tick(). The code number is not reused.
WF-213
Watch/subscribe path targets a list item by numeric index
A watcher or subscription registered a path like items.0.name. This is an anti-pattern: reactivity tracks items by object identity, so the index in a change path reflects the item's position when it was first observed, so after a splice, removal, or reorder the watcher fires for the wrong slot or goes silent. Watch the array (or a computed over it) and track items by id instead, e.g. watch: { items() { ... } } or a computed like activeItem() { return this.items.find(i => i.id === this.selectedId) }. The Communication page covers the watch block. Warning severity (logged via console.warn, never throws); dev-mode only, stripped from production builds.
WF-214
Zero-arg computed in a list row reads an item property via this
A computed referenced inside a data-list row template was declared with no parameters, and its body reads this.<prop> where <prop> is not on the component's state or computeds but is a property of the current list item. Zero-arg computeds evaluate at component scope, so that read silently resolves undefined. Item-level computeds receive the item as their first argument: declare it, e.g. priceLabel(item) { return '$' + item.price }. A zero-arg computed that reads only component state is legitimate inside a row and never triggers this warning. The Item-Level Computed Properties section teaches the parameter rule. Fires once per component and computed; warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-215
Component or store re-registered with a different definition
A component or store was registered under a name that already exists, and the incoming definition differs from the stored one. Registration is first-write-wins, so the original is kept and the new definition is ignored. This is almost always an accidental collision (two components sharing a name, a hot reload without teardown). To replace a definition intentionally, call wildflower.unregister('<name>') first, then re-register; or give the new one a distinct name. The comparison hashes method source, so two definitions that share method names but differ in a method body are still flagged; an identical re-registration (the same definition scanned twice) does not warn. The Replacing a Definition section covers the intentional path. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-216
State property read thousands of times per frame (sustained hot loop)
One state property is being read through the reactive facade at hot-loop rates, sustained across animation frames. A facade read costs roughly 100x a plain property read; that is proxy physics, and every fine-grained framework pays it. The fix is one line: hoist the value to a local before the loop (const speed = this.state.speed) and read the local inside it. For per-entity hot data, pool entities are plain objects with zero proxy cost. One-shot sweeps (building a large structure once during init) do not trigger this warning; it fires only for reads that recur frame after frame, and only once per property name. The Architecture Patterns section shows where hot-loop state belongs. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-217
Computed wrote to state during evaluation
A computed mutated tracked state while it was being evaluated, including an in-place sort or reverse. Computeds must be pure. The mutation invalidates the computed while it runs, and anything bound to it (a data-list, a binding) can silently render empty or stale. Copy before mutating (return [...items].sort(...)), or move the write into a method. (The framework's own internals write through an untracked escape and stay silent; that escape is not part of the application surface.) Warned once per computed. The Chaining, Filtering & Sorting section shows the copy-before-sort idiom. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-218
Name collision across definition buckets
The same name is defined in more than one bucket of a definition: a method colliding with a state key or a computed, or a key defined in both state and computed. One of them is shadowed wherever the bare name resolves. For state/computed collisions the computed wins everywhere except explicit this.state.key reads. Rename one. Warned once per definition. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-219
Definition key ignored
A top-level key in a component, store, plugin, or pool entity definition is not a function and is not part of the definition contract, so it was ignored. State values belong inside state: {}; only methods live at the top level, never in a methods or actions block. Underscore-prefixed keys are the documented stash and stay silent. Warned once per definition with a hint for the specific key. The Store Definition Mistakes section shows the correct shape. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-220
Assignment to a computed property
Computed properties are read-only derived values. The assignment was ignored and the property keeps computing from its inputs. Store the value in state instead, or rename the computed if you meant a state field. The Computed Properties page draws the derived-vs-stored line. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-221
batch() called without a function
wildflower.batch(fn) groups writes into one flush and requires a function argument; the call was a no-op. Pass the writes inside a function: wildflower.batch(() => { ... }). The write-to-DOM section shows batching in context. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-228
Validation rule declaration invalid
A rules: entry could not become a working rule and was disabled. String checks must parse and every variable they reference must be a state or computed name; the context states the specific problem, including any unknown variable, so a typo cannot silently gate a form. Per-field validation and the other rules keep working. Dev-mode warning at first validation. The Cross-Field Rules in Depth section states the contract.
WF-229
Validation rule check threw
A function-form rule check raised an exception, so the rule was skipped for that validation pass rather than blocking or passing the form on an error. The other rules and per-field validation still ran. Fix the check; the warning includes the rule name and the error message, once per rule. Dev-mode only. The Cross-Field Rules in Depth section covers the check contract.
WF-234
Validation rule returned something that is not a verdict
A function-form rule must return a value that reads as true when the rule holds and false when it does not. Three returns are never a verdict and each one fails quietly in its own direction, so the rule is skipped and named instead of coerced. A promise is always truthy, so an async check would report success no matter what it eventually resolved to; rules run synchronously, and work that has to wait belongs in the submit handler. undefined is always falsy, usually a missing return, and would block the form permanently. A string is truthy, so it reports success even though it reads like a failure message. Return true when the rule holds and put the wording in the rule's name or its message:. Dev-mode only, once per rule. The Cross-Field Rules in Depth section states the verdict contract.
WF-235
Item-level list computed returned a Promise
Computeds may return a promise at component, store, and plugin scope, where the entity tracks the request and updates the binding when it lands. A computed that takes the item as a parameter runs per row through the list renderer instead, which does none of that tracking. The promise never resolves into the row, so the binding renders the promise object as text, and a list of N rows would issue N uncoordinated requests. Item-level computeds must be synchronous. Fetch the collection once in a component-level computed, derive the row array from it in a second computed, and bind the list to the derived array; the Async Computed Properties page shows the pattern. Fires once per component and computed; warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-301
Error resolving data in context
Context data resolution failed during binding evaluation. The bound property path may be invalid or the data structure has changed unexpectedly.
WF-302
Missing component instance in context
A context operation requires a component instance but none is available. The component may have been destroyed.
WF-303
Error updating context
The context update process encountered an exception. This is typically caused by invalid data or a corrupted context state.
WF-304
Error in context dependency notification
Failed to notify dependent contexts of a data change. A dependent binding or computed property may have an error.
WF-401
Template not found for list
A data-list element resolved no item template. The development build reports the cause it found: row markup written as direct children instead of inside a <template>, a container inside <svg>, where the HTML parser never creates a real template and the element survives as inert with no content fragment, or no template in any searched source (inline child, data-use-template reference, inherited templates). Add a <template> child. For repeated SVG primitives use a data-pool, whose template does work inside <svg>; failing that bind a fixed set of elements. The template rule section states the requirement.
WF-402
Error rendering list
The list rendering process threw an exception. Check that the list data is a valid array and that template bindings reference valid item properties.
WF-403
Error updating list item
Updating an existing list item's bindings failed. The item data may have an unexpected structure.
WF-404
Error removing list item
Removing a list item from the DOM failed. The element may have already been removed or detached.
WF-405
Error in append optimization
The optimized append path for adding items to the end of a list encountered an error. The framework will fall back to a full re-render.
WF-406
Error in swap optimization
The optimized swap path for reordering list items encountered an error. The framework will fall back to a full re-render.
WF-407
Error in sparse update optimization
The optimized sparse update path (updating a subset of list items) encountered an error. The framework will fall back to a full re-render.
WF-408
data-pool container name is not in the component's pools block
A data-pool container names a pool that does not appear in the component's declared pools: {} block. Pool names must match exactly; code that populates getPool('items') never reaches a container written as data-pool="itmes", so the container renders nothing. This is almost always a typo, and the warning suggests the closest declared name. A markup-only pool (no declaration, populated programmatically by the exact same name) is legitimate and stays silent. The data-pool section covers name resolution. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-409
Pool has a container but was never populated
A data-pool container and its template are wired correctly, but nothing was ever added to the pool by the time the page settled, so nothing renders. Populate it from the component with this.getPool('name').add({ id: 1, ... }) or through the pools.name handle. If the pool fills later by design (for example on user interaction), this note can be ignored; it fires once and only in development builds. The pool insertion section shows the population calls.
WF-410
Entity spawns produce mixed shapes (hidden-class deoptimization)
Two spawn paths in one pool produced entities with different fields or a different field order. V8 gives a pool one fast hidden class only when every entity shares the same shape; once shapes diverge, every hot-loop read in the pool slows down. This is platform physics rather than a framework rule. Make all spawn paths build entities with the same fields in the same order: initialize missing fields up front (null or 0), or split differently-shaped entities into separate pools. Fields filled by entity.state defaults count as normalized and stay silent. Fires once per pool, showing both shapes. The entity.state section shows shape normalization. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-411
entity.computed pool reached a frame-budget size
A pool that declares entity.computed properties reached 200 entities. Entity computeds are uncached by contract (they re-evaluate on every read, roughly 60us per entity per flush measured), so on a per-frame pool this cost lands on every animation frame. For per-frame pools at this scale, store the derived value as a plain data field updated on mutation, or mark non-animating entities static with data-pool-static="prop". Passive pools (data-pool-static on the container) never flush per frame and stay silent. Fires once per pool. The entity.computed section states the cost and the alternative. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-412
Named or typed template never resolved
A template lookup by name or type found nothing to render, or found something unusable: a configurable template missing from the hierarchy with no fallback, a target component that does not exist, a polymorphic item type with no matching data-type template and no default, a template with empty content, or duplicate item-template names (the first wins). The warning includes the template or type it searched for. Check the name against the defining component, or add a fallback/default template. The Template Hierarchy Lookup section states the search order. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-414
Index-dependent method or direct mutation on pool storage
Pools use swap-with-last storage, so positions reshuffle on every removal and index-based operations would hit a different entity than intended. In dev builds pool.splice(), pool.pop(), pool.indexOf(), and pool.slice() exist as throwing stubs that explain this, and mutating pool.items directly is caught by a consistency check at the next API call. Iterate pool.items freely; mutate only through the pool API (add/remove), use remove(key) to delete and at(i) for stable DOM-order access. Production keeps the raw array (pull mode's zero-overhead contract). Dev-mode only. The Array-like readers section lists what the pool exposes instead.
WF-415
Pool entity key missing or duplicate
An entity added to a keyed pool is missing the declared key property, or carries a key the pool already holds; the entity is not registered. Give every entity a unique value for the pool's key property before adding it. The data-key section states the uniqueness rule. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-501
Error evaluating binding expression
A data-bind expression failed to evaluate. Check for typos in property names or invalid JavaScript expressions. Also emitted as a warning when store shorthand ($store.path) is used in data-model. The Expressions page is the syntax reference.
WF-502
Error evaluating class binding
A data-bind-class expression failed to evaluate. Check that the expression returns a valid string or object. The Style Bindings page shows the accepted shapes.
WF-503
Failed to create HTML binding context
Creating a context for a data-bind-html binding failed. Check that the binding path is valid.
WF-504
Error updating conditional context
Updating a data-show or data-render conditional context failed. Check that the bound expression evaluates to a boolean-like value. The Conditional Rendering page covers the expression forms.
WF-505
Class binding shape mismatch
A data-bind-class binding received a value that is not a string. The element-level path expects a space-separated class string. Inline expressions can use the {'class-name': condition} object form, but a computed property should return the resolved string itself. The framework coerces the value (truthy keys joined to a string, or the value stringified) so the page keeps rendering, but the underlying mismatch should be fixed in your code. The Class Binding with Computed Properties section shows the resolved-string pattern.
Wrong: computed: { classes() { return { 'is-active': this.active }; } }
Right: computed: { classes() { return this.active ? 'is-active' : ''; } }
WF-507
data-prop path unresolvable in the parent
A data-prop-* (or data-props) value looked like a path, resolved to undefined, and was still absent from the parent's state, computed properties, and methods after the page settled. A typo'd path is indistinguishable from a real prop at resolution time, so the check waits out the init window first; a parent that sets the key in init() stays silent, as does a prop whose declared default absorbed the miss. The warning suggests the closest matching parent name. If the parent genuinely provides the value later (for example after a fetch), the note can be ignored. The Prop Value Resolution section states the lookup order. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-508
Prop attribute names a prop the component never declared
A data-prop-* attribute (or a key inside data-props) was passed to a component that never declared that prop, so the value is never read. Only declared props are consumed; this is the prop-name sibling of WF-507's path typo (data-prop-titel against a declared title, or data-prop-user-id against userId). When the component declares props, the warning suggests the closest declared name; when the component has no props block at all, every prop attribute on it is dead and the warning shows the declaration to add (props: { title: { type: String } }). Fix the attribute name or declare the prop. The Props Definition Reference shows the declaration forms. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-509
Binding validation
A binding references a name that does not resolve: a data-bind/data-model/data-show/data-render path, an identifier inside a class or style binding expression, a nested path segment, a type hint that does not match the value, or a data-action method that does not exist on the component. The development build warns at bind time with a did-you-mean and the list of available names. On by default in development builds; disable with debug: false. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-510
data-props attribute failed to parse
The bulk data-props attribute takes two forms, and this warning belongs to the second. The object-expression form (data-props="{ title: cardTitle }", unquoted keys, values as parent state paths) never parses as JSON and never raises this. The quoted-key form (data-props='{"title": "Dashboard"}', values as literals) must be valid JSON, and this fires when it is not, so no props were passed. Common causes are single quotes around keys and strings, or unescaped quotes inside values. For dynamic values, prefer the object-expression form or individual data-prop-* attributes with paths. The data-props section shows both forms. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-512
A data-model root names both a state key and a store
A data-model path's first segment matches a key the component's own state declares and the name of a registered store. One rule decides, the same rule bare names follow everywhere in the framework: the component comes first. The binding is component state in both directions, since typing writes it and repaints read it, and the same-named store is never touched. The store-backed form pattern is the fallback for roots the component does not own, so if the store is what you meant, rename the local state key or the store. This note exists because a name serving two masters reads ambiguously even when the resolution is well-defined; it is said once per component and root. The Store-Backed Inputs section covers the pattern and the rule. Warning severity: dev-mode only, stripped from production builds.
WF-601
Error in action handler
A data-action handler method threw an exception. Check the method referenced in your data-action attribute. The Events page covers action handlers.
WF-602
Error in component method
A component method execution failed. Check the method for runtime errors such as accessing undefined properties.
WF-603
Cannot emit: component instance not found
emit() was called but the component instance could not be located. Ensure the component is mounted and initialized. The Communication page covers emit().
WF-604
data-action targets a reserved lifecycle name
A data-action points at init, tick, destroy, or another lifecycle hook. Lifecycle names run on the framework's schedule, not on events: tick() runs every animation frame, destroy() tears the component down, and with the element still in the DOM the next scan auto-resurrects it. Rename the handler to a specific verb (increment, handleClick, refresh). The Method Naming Mistakes section covers the reserved list. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-605
Stale event API in a replayed action
An action fired before init() finished was queued and replayed afterward, and the handler then called preventDefault(), stopPropagation(), or stopImmediatePropagation() on the original event. By replay time the browser has already processed the event, so the call is a no-op. Put data-event-prevent on the element to block the default reliably; the framework intercepts before user code runs. The Early Submit Edge Case section walks the exact scenario. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-606
$entity.path in data-action
$entity.path is a read accessor for external state and cannot name an action handler; actions are component-locked by design. To delegate to another entity's method, define a one-line wrapper on the component: bump() { this.getStore('name').bump(); }. The warning shows the exact wrapper for the path you wrote. The Communication page covers cross-entity calls. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-701
Route not found
Navigation attempted to access a route that hasn't been defined. Check your route configuration. The Basic Setup section shows route definitions.
WF-702
Target route not found for alias
A route alias points to a target route that doesn't exist. Verify the alias target matches a defined route path. The Route Config Options table documents alias.
WF-703
Error in route guard
A navigation guard function (beforeEnter, beforeLeave, etc.) threw an exception. Check the guard function for errors. The Route Guards page covers the guard contract.
WF-704
Navigation queue exceeded retry limit
The navigation queue has exceeded its maximum retry attempts. This usually indicates a redirect loop in your route guards. The Navigation Cancellation section shows the levers.
WF-705
Named route not found
Navigation by name references a route that doesn't exist. Check the name property in your route definitions. The Named Routes section shows the property.
WF-706
Invalid route configuration
A route definition has an invalid structure. Routes require at minimum a path property. The Basic Setup section shows the shape.
WF-707
Router already initialized
Attempting to initialize the router more than once. The router should only be configured and started once per application.
WF-708
No route matched for path
No route pattern matches the requested URL path. Consider adding a catch-all route (path: '*') for 404 handling. The 404 Handling section shows both approaches.
WF-709
Error in route handler
A route's handler function threw an exception during execution.
WF-710
Error loading route component
An async/lazy-loaded route component failed to load. Check the network request and module path. The Lazy Route Components section covers the feature.
WF-711
Error in scroll behavior
The scroll restoration or positioning function threw an exception after navigation. The Scroll Position Restoration section covers the surface.
WF-712
Error in route lifecycle hook
A route lifecycle hook (beforeEnter, afterEnter, etc.) threw an exception. The Route Guards page covers the hook contract.
WF-801
Error during SSR activation
Server-side rendered component activation failed. The server-rendered HTML may not match the expected component structure. The SSR Troubleshooting table maps symptoms to causes.
WF-802
Error during hydration
Hydrating server-rendered HTML encountered an error. Ensure the server-rendered markup matches the client component's expected structure. The SSR Troubleshooting table maps symptoms to causes.
WF-901
Store component name must be a string
wildflower.store() was called with a non-string first argument. The store name must be a string. The Stores page shows the registration form.
WF-902
Store component definition must be an object
wildflower.store() was called with a non-object second argument. The store definition must be a plain object. The Stores page shows the definition shape.
WF-903
Error in store init hook
A store's init() lifecycle hook threw an exception. Check the store's initialization logic. The Advanced Stores page covers the lifecycle.
WF-904
Error creating store component
The store creation process failed. Check the store definition for structural errors.
WF-905
Error in external() accessing store
external() failed when accessing a store. Verify the store name and property path are correct. The Communication page covers external().
WF-906
Error in store subscription callback
A store subscription callback threw an exception. Check the function passed to the store's subscribe() method. The Communication page covers store subscriptions.
WF-907
Failed to create default app-store
Automatic creation of the default application store failed. This is an internal initialization error.
WF-908
Store path written from inside its own notification
An onStoreUpdate handler wrote the store path it was being notified for, which would loop forever. The engine drops the nested notification and keeps the write, so the cycle cannot hang the page; the warning identifies the store and path. Derive the value with a computed instead, or write a different path. The onStoreUpdate section teaches the hook's correct use. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-909
Subscribed or watched store never registered
A component subscribes to, watches, or path-subscribes a store name that nothing ever registered. The miss is reported (error severity for subscribe:, warning for watchers) and init continues best-effort so the rest of the component works. Fix the name, or register the store before the component initializes. Dev-mode only, stripped from production builds. The subscribe section shows the declaration whose names are checked.
WF-910
Timed out waiting for a subscribed store
A subscribed store exists but did not become ready within the wait window (default 5000ms; per-component override via subscribeTimeout in the definition). The component's onError hook receives the timeout and init continues best-effort. Check the store's async init() for work that never resolves. The subscribe section covers the readiness wait. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-940
A named operation did not inherit the query-level confirmation
A query-level confirmation: reaches update and create only. Every other operation named in to: declares its own or has none, the same rule body: follows.
The write still succeeds. What is lost is the reconciliation: with no confirmation the response is treated as transport, so the query invalidates and refetches, and that refetch clears the stored ETag first, which makes it a full collection body on every write of this shape.
The endpoint that answers a named operation with the updated record is the common case, so the response usually carried exactly what the row needed.
Declare confirmation on the operation itself to reconcile from its response, or leave it alone if the refetch is what you want.
delete never fires this, since 204 No Content is the ordinary answer and carries nothing to confirm.
Named operations covers the per-operation declarations.
Warning severity: dev-mode only, stripped from production builds; the refetch happens in every build. Fires once per query.
WF-950
External write to a query-owned store
A field on a query's backing store (rows, isLoading, isStale, error, syncError, lastSync) was assigned from application code. Query stores are engine-owned: the fetch pipeline rewrites them on every sync, so an application write survives only until the next refresh replaces it. The supported pattern is to mutate the data source, then call wildflower.getQuery('name').invalidate(). The write still lands, since a deliberate optimistic update is legitimate; the warning fires once per store. The Writes & Optimistic Updates page teaches patch(), the sanctioned form of this write. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-951
Query name already registered
A second wildflower.query() call used a name that is already registered. The second registration is ignored and the existing query's handle is returned, so config changes in the second call never apply. Declare each query once, at module scope. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-952
Query name collides with an existing store
Queries and stores share one entity namespace, because every query is backed by a store of the same name. A wildflower.query() call whose name matches an existing store is refused (null is returned) rather than silently taking over the store's data. Pick a name no store uses. The Entity Model page explains the shared namespace. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-953
Query from is not a URL or function
The from option must be a URL string or a function returning the data (or a Promise of it). Registration is refused (null is returned). There are no other source types: anything beyond a URL is expressed as a function. The Sources and Refinement page covers both forms. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-954
Sub-second poll rung
A numeric refresh rung below 1 is almost always a units mistake: poll values are seconds, so 0.5 means twice per second (120 requests per minute against the source), where the author usually meant "every 30 seconds". The rung still runs as declared. If sub-second polling is genuinely intended, the warning can be ignored. The Refresh Ladder section defines the rung values. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-955
No such query is registered
Fires in two shapes that share this code: a data-query attribute in markup names a query that was never declared (the element is left untransformed and never activates), or getQuery('name') is called for an unregistered name (returns undefined). Register the query with wildflower.query('name', { from: ... }) before the markup mounts, and check for typos between the attribute and the declaration. The Data Queries page shows the declaration surface. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-956
data-seed is not valid JSON
A data-seed attribute on an adopted row or query element could not be parsed as a JSON object, so its fields were ignored; the row keeps only what the display text parse recovered. Common causes are single quotes inside the JSON, unquoted keys, or a non-object value (arrays are ignored by design). The data-seed section states the seed contract. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-957
The sse rung needs a stream URL
The 'sse' rung opens an EventSource, which requires a URL. When from is a URL string it doubles as the stream endpoint, but when from is a function there is nothing to connect to, so the rung is skipped (other declared rungs still run). Add a stream: option naming the SSE endpoint. The Server-Sent Events section shows the declaration. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-958
SSE message was not valid JSON
The stream contract: a JSON message body is applied as the new result, an empty message is an invalidation signal (conditional refetch). A non-empty message that fails to parse as JSON fits neither, so the engine degrades it to an invalidation and refetches, keeping data correct at the cost of one extra request. Fix the server to send JSON bodies or empty invalidation pings. Named once per query per page load; later non-JSON messages still invalidate, silently. The Server-Sent Events section states the two-message contract. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-959
Record query resolved null
A record-shaped query's source resolved to null or undefined. This is a valid empty context by design: bound fields render empty and nothing throws, matching "no result yet" states like a logged-out session. The warning exists because a permanently null record often means the source returns a wrapper shape ({ data: {...} }) rather than the record itself. Named once per query per page load, across both delivery paths (fetch and stream). The Record Semantics section covers the null-record contract. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-960
Append received rows without the declared key
An append refresh (refresh({ params, append: true })) received rows that lack the query's declared key field. Accumulation identifies rows by key to dedupe and merge, so keyless rows would duplicate endlessly; the engine applies the result as a plain replace instead and warns. Give appended rows the declared key, or declare the key the source actually returns. The append section states the key requirement. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-961
refresh() received unexpected options
refresh() takes an options object with three recognized fields, params, append, and clear. Any other key is almost always request parameters passed directly (refresh({ status: 'open' })), which the engine cannot distinguish from an option name and therefore never sends. Nest them: refresh({ params: { status: 'open' } }). Keeping parameters inside params is what guarantees no request parameter can ever collide with an option name. The refresh still runs, without the stray values. The URL Sources section shows the nesting. Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-962
Incoming rows drifted from the data-expect declaration
Incoming rows broke an element's data-expect="field:type, …" declaration, either a declared field missing from the rows or one present with a different primitive type.
The context gives the query, the field, and which source carried the drift (fetch, stream, ssr, or patch).
A null value counts as data rather than drift, and a token with no type checks presence alone.
Each distinct drift warns once per query, so polling never floods the console.
This is a tripwire rather than a validator: nothing is coerced, transformed, or rejected, and rendering proceeds unchanged.
For real validation, wrap the function source with a validator.
Declaring the Expected Shape teaches the declaration.
Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-963
data-query element has no component ancestor
A [data-query] element sits outside any component, so nothing will ever process it.
The query transform runs during component binding, so an element with no data-component ancestor is skipped entirely, with no fetch, rows, or error state, leaving markup that looks correct and does nothing.
Wrap it in a component; an empty definition is enough, as in wildflower.component('shell', {}) with <div data-component="shell"> around the query element.
Detected by a post-scan sweep and warned once per element.
Where It Runs states the rule.
Warning severity (console.warn, never throws); dev-mode only, stripped from production builds.
WF-964
write() needs a to function declared on the query
write() was called on a query that never declared to, so there is no transport to hand the item to and the call rejects rather than applying an optimistic update that could never sync.
A query describes its resource in both directions: from for how rows come in, to for how a write goes out.
Declare it on the query, as in to: item => fetch('/api/orders', { method: 'POST', body: JSON.stringify(item) }).
Development builds also warn at registration when to is declared in a shape that cannot route (WF-971).
Declaring the Destination shows all three forms.
Error severity (the promise rejects, so .catch and an awaited try/catch both see it); present in all builds.
WF-965
write() resolved with something that is not the row's record
Two shapes reach this, and both fall back the same way: a keyed write resolving with an object that has no key field (usually a status envelope like { success: true }), or a resolution that is not an object at all, such as confirmation: r => r.ok.
Neither can be applied as the row's record, so the engine treats the resolution as nothing and invalidates; the next conditional fetch carries the truth.
Record queries see only the second half, since their writes are keyless and a keyless object is simply the record.
To keep that fallback without the warning, resolve with nothing.
To apply the response directly, echo the key onto it: .then(r => r.json().then(j => ({ ...j, id: item.id }))).
Telling the query what happened covers confirmations.
Warning severity (console.warn, never throws); dev-mode only, and the invalidate fallback applies in all builds.
WF-966
A container written to state holds a facade-wrapped object three or more levels deep
A value written to reactive state contains a reactive facade nested three or more levels inside it.
Reading state hands back facades, so a copy of state carries them along: this.items = this.items.filter(...), [...this.items, item], and this.items.map(i => ({ ...i, done: true })) all do.
The engine unwraps the value you assign and the first two levels inside it on every write, in every build, so those forms store plain objects and work as they do elsewhere.
A facade deeper than that reaches the raw state graph, each later read wraps it again, update routing degrades, and every read of the container walks a growing proxy chain.
Build the deeper copy from unwrapped data, as in wildflower.toRaw(this.items), or copy only the level you are changing.
Detected with a bounded scan and warned once per stored container.
State covers wildflower.toRaw.
Warning severity (console.warn, never throws); dev-mode only, and present in every tier's development bundle since any component with reactive state can reach it.
WF-967
Unrecognized refresh rung token
A token in a refresh declaration matches no rung, so the query runs without the rung you meant to declare.
The valid tokens are a bare number for the poll interval in seconds, 'focus', 'reconnect', 'sse', 'etag:N', 'fresh:N', and 'once'.
The usual cause is inventing a prefix for the poll interval: 'poll:15' is not a token, and the poll rung is the bare number, refresh: [15].
The Refresh Ladder lists every valid token.
Warning severity (console.warn, never throws); dev-mode only, and the token is ignored in all builds.
WF-968
Query persist must be true or a storage-key string
The persist option is neither true nor a non-empty string, so persistence is off for this query, which otherwise runs normally.
persist: true stores the last confirmed server rows under a derived key (wf:query:<name>), and persist: 'my-key' chooses the key directly, which is how per-user keys are done.
On the next load a query with stored rows paints them immediately, marks itself isStale, and revalidates.
Persistence covers the whole surface.
Warning severity (console.warn, never throws); dev-mode only, and an invalid option is ignored in all builds.
WF-969
write() was called without the query's key field
An item passed to write() with no value for the key identifies no row, so the write is rejected before anything happens: nothing applies optimistically and no field claims are taken.
Include the key alongside the fields being changed, as in write({ id: 7, done: true }), or use create() to add a row instead of changing one.
The query's shape decides this, not whether you spelled out key:, since key defaults to id and a query rendering a list is keyed either way.
Record queries hold one record and accept unkeyed payloads; a query bound as both counts as a list, because a list binding means its rows carry keys.
Writes teaches the rule.
Error severity (the promise rejects, so try/catch and syncError both see it); the rejection happens in every build, while the diagnostic text is dev-mode only.
WF-970
The query params function threw
A params function threw, so the request departed carrying only the values passed explicitly to refresh({ params }).
The usual cause is reading through something not there yet, such as a route store that has not populated or a nested property on an object that is still null.
Guard the read or supply a default.
This matters more than it looks because the function resolves once per request, including internal refetches from a settling write, a poll tick, a focus or reconnect, and a missed-arrival catch-up.
Named once per query per page load.
URL Sources shows the params-function form.
Warning severity (console.warn, never throws); dev-mode only, and the fetch proceeds identically in all builds.
WF-971
A to or create declaration is not a shape the query can route
A to or create declaration is not a shape the engine can route.
The valid forms are a URL string (to: '/api/items/:id', becoming update at PATCH and delete at DELETE), a map of named operations, or a function.
This fires on an entry with no url, a body or confirmation that is not a function, an array, or create declared inside the to map.
create is its own top-level key because it alone mints identity: it is called as create(item), its URL must not carry the key token, and a rejection removes a row that only ever existed optimistically.
The malformed operation is dropped, so calling it later raises WF-974.
Declaring the Destination shows every routable shape.
Warning severity (console.warn); dev-mode only, though the operation is unavailable in every build.
WF-972
A :token in the request URL had no value, so nothing was sent
On a read this is a wait rather than a failure.
Nothing is recorded, rows on screen stay put, and the query fetches when the value lands, so an unresolved route parameter is the usual and harmless cause.
Dev builds name the wait once per token, which is how a misspelled token still surfaces.
On a write the promise rejects and identifies the token, because a write runs only when the application calls it.
Carry the value on the item being written, or supply it from params.
URL Templates covers token resolution.
Error severity on the write path and no error at all on the read path; the write rejects in every build, while the diagnostic text is dev-mode only.
WF-973
A :token in a declared URL names nothing the query can supply
The declaration-time half of WF-972, raised at registration instead of at the first request, in two cases.
A token in from that a static params object does not supply is almost always a typo. (Only from is checked, since to URLs interpolate the item's own fields and a parent id on the row is legitimate.)
The other is a create URL interpolating the key token, which resolves only when create() is passed a key you made, as in the client-generated-id pattern against a PUT endpoint.
Where the server issues the key instead, point create at the collection URL; a create reaching the transport with a framework-minted key and such a URL is refused in every build, since that address names a temp id the server never issued.
URL Templates covers token resolution.
Warning severity (console.warn): dev-mode only.
WF-974
write() or create() named an operation the query does not declare
A map declares exactly the operations it lists, so one it omits is unavailable rather than approximated, and an undeclared name never falls back to update.
The message states the operation asked for and lists the declared ones.
The usual causes are a spelling difference between declaration and call site, a create() on a query with no create key, or a delete on a query that declares deleted but no delete route (which also warns at registration, WF-975).
Naming an operation on a query whose to is a function raises this too, since a function receives the item and nothing else and carries no operation hint.
Named operations shows the map form.
Error severity (the promise rejects, nothing applies optimistically, no request departs); raised in every build.
WF-975
The delete operation and the declared deleted field disagree
The declared deleted field and the declared delete route disagree, in one of two directions.
Declaring deleted: 'removed' beside a map with no delete entry warns at registration and errors at the call site, rather than being refused outright, since a resource may carry a server-driven tombstone field for arriving rows while the client never issues deletes.
The reverse is write('delete', item) on a query declaring no deleted field: the request departs, but nothing marks the row deleted on screen, so it stays visible until the next sync.
A named delete always applies the declared tombstone itself, so one map entry cannot behave differently by derivation than by name.
Deletes teaches both halves.
Warning severity at registration; the call-site failure is WF-974.
WF-976
The written item merges no fields, so nothing can roll back
An item carrying only the key, as in write('favorite', { id: 7 }), claims no fields, so its rejection rolls nothing back and later writes to the same row have nothing to order against.
The write machinery works over a row key and a field: it applies an optimistic value, claims the field, and reverts the fields a write still owns when it fails.
Include the fields the operation changes, as in write('favorite', { id: 7, favorited: true }).
The request is unaffected and still departs, so this is correct behavior that reads as a bug, named once per operation.
Named operations shows the field rule.
Warning severity (console.warn): dev-mode only.
WF-977
An update or create carries fields but declares no body
An update or create is about to depart with no body while the item passed to it carries fields, which is a request that succeeds and changes nothing.
An operation sends no body unless one is declared, because payloads differ within a single query: a body-less DELETE beside an envelope-carrying POST is ordinary, and guessing for one would send the wrong thing for the other.
The query-level body covers update and create, and every other operation declares its own on its entry.
Declare the shape with body: item => item for a plain API, or body: item => ({ article: item }) for one expecting an envelope.
Warned once per query.
Declaring the Destination covers body.
Warning severity: dev-mode only.
WF-978
A declarative option cannot be honored beside a function from
A function from is called with no arguments and builds and parses its own request, so params and select have nothing to act on for reads and the function must derive its own values and return its own rows.
Declaring them anyway states an intent the framework cannot honor.
There is one exception: params still feeds :token segments in write URLs, so a query keeping a function from while declaring its writes is a supported shape, and no warning is raised when a declared operation URL carries a token.
Function Sources states which options a function form honors.
Warning severity (console.warn) at registration; dev-mode only.
WF-979
A refetch dropped values the last refresh({ params }) had applied
Values passed to refresh({ params }) apply to that one fetch.
The next refetch the engine starts on its own resolves the declaration again and reasserts its own values, which on screen reads as a value spontaneously reverting, since the refetch was a poll tick, a stream invalidation, a focus refresh, or the revalidation after a write settled.
The warning fires at that refetch, reports what was dropped, and fires once per override.
A query that never refetches on its own cannot reach it, an explicit refresh() clears the override quietly, and an override passed with append: true never arms it.
When a value should persist, move it into whatever params derives from, such as a store field the params function reads, and keep refresh({ params }) for genuinely one-off requests.
Paged and Infinite Results shows the rewrite for a paged query beside a rung.
Warning severity: dev-mode only.
WF-980
The read response did not arrive as an array of rows
A list-shaped query expects an array, and a response that is not one becomes a single row whose fields are that object's.
An API answering { articles: [...], articlesCount: 47 } therefore renders one row with the fields articles and articlesCount.
Name the array with select: d => d.articles.
The companion case is a response, or a select, resolving null or undefined, which empties the list; the message says which happened, since "the server sent nothing" and "the transform missed" look identical on screen.
Record-shaped queries never raise this, since a single object is their answer.
Named once per query per page load.
Shaping the Response teaches select.
Warning severity: dev-mode only.
WF-981
A headers declaration is not an object or a function, or it threw
This fires when a headers declaration resolves to something that is not an object, when a headers function throws, or when a config({ headers }) key is not an origin.
The request still departs, without those headers.
Headers come from two places: config({ headers }) sets a default scoped by origin, and a query's own headers overrides it key by key.
Either may be an object or a synchronous function, and the function runs once per request attempt, retries included, so a refreshed token is the one actually sent.
Named once per query per page load, with the config-key check suppressed once per config object.
Headers and Credentials covers both forms and why the keys are origins.
Warning severity: dev-mode only.
WF-982
create() was called on a record-shaped query
A query bound without a <template> is record-shaped, and its subtree binds one record.
create() makes a new row, which a binding that renders one record has nowhere to show, so the call is rejected rather than appending something invisible.
Use write(item) to change the record you have.
If the query really holds many rows, bind it as a list with a <template> child and create() works as documented.
A query bound both ways counts as a list, so a record view sitting beside a list view of the same query never raises this.
Writes covers the shape rules.
Error severity (the promise rejects); the rejection happens in every build, while the diagnostic text is dev-mode only.
WF-983
Query retry must be a number
The retry option is a plain attempt count, as in retry: 3, clamped to 0-10 with a fixed doubling backoff, and it takes no policy object.
Any other shape coerces numerically, and most coerce to 0, which turns retry off entirely; retry: { max: 3 }, the shape several data libraries use, declares no retries at all.
That is otherwise invisible, since a retry ladder only shows itself when a request fails.
The warning reports the shape at registration and states the value it actually coerced to.
Automatic Retry states the whole surface.
Warning severity (console.warn, never throws); dev-mode only, and the coerced value applies in all builds either way.
WF-984
Declared headers cannot apply to the sse stream
A query with declared headers opened an sse stream, which cannot carry them.
The limit is the platform's: the browser's EventSource constructor accepts no headers, so the stream connects anonymously even though every fetch on the same query authenticates.
A server requiring the header rejects the stream, and on a query that has never synced that rejection is easy to miss, since the connection retries quietly in the background.
Named once, at the moment the stream opens.
Authenticate the stream another way, such as a token in the stream URL's query string or cookies on a same-origin stream.
Headers and Credentials covers where declared headers do apply.
Warning severity: dev-mode only, stripped from production builds.
WF-985
Query initial must be an array of rows
The initial option seeds rows to paint before the first fetch answers, and it takes an array in every shape.
A record-shaped query is the trap, since its natural seed reads as a single object while the seed is still a one-element array, as in initial: [{ name: 'Loading…' }].
Any other shape is ignored, which used to mean no seed, no warning, and exactly the loading flash the option exists to remove.
Named at registration.
Query Shapes shows the record seed.
Warning severity: dev-mode only, and a non-array seed is ignored in all builds.
WF-986
Declared headers rode a redirect to another origin
A response revealed that a request carrying declared headers was redirected to another origin.
On such a hop the platform removes Authorization and forwards every other header, so an API key or tenant header declared for the first origin arrives at the second.
No framework code runs between the two requests, so the hop can be reported but not intercepted.
Named once per query, on the first response that reveals it, for reads and writes alike; a same-origin redirect never warns.
If the redirect is expected, point from or to at the final URL so the request starts where it ends.
If it is not, this is the earliest visible sign that credentials are leaving the origin they were declared for.
Headers and Credentials covers the scope guarantee.
Warning severity: dev-mode only, stripped from production builds.
WF-987
write() received an undefined-valued field
A field passed to write() as undefined is treated as absent, since undefined is not a value the wire can carry.
JSON serialization already drops it from the request body, so letting it through on the client would write undefined over the row's real value while the server never hears about the field.
The rule matches the confirmation format: null clears a field, an absent field is left alone, and undefined means absent everywhere, so it is not merged, claimed, or sent.
Pass null to clear a field, or omit it to leave it alone.
The dropped fields are named once per query.
Warning severity: dev-mode only, stripped from production builds.
WF-988
A persist save landed inside the clearPersisted() window
A query delivered data shortly after clearPersisted() ran, and the save that would normally follow was suppressed, because a clear holds through a short transition window. Without the window, a response already in flight at sign-out would write the snapshot right back. This is expected during a logout transition and needs no action; persistence resumes on its own once the window lapses. For full soft-logout safety on a page that never navigates, unbind the query's elements before clearing so nothing keeps syncing on the signed-out user's behalf. The Persistence section covers the sign-out story. Warning severity: dev-mode only, stripped from production builds.
WF-989
The sse rung is connecting to a JSON endpoint
With stream: absent, the sse rung connects to the query's from URL, which an ordinary JSON API does not serve as an event stream.
EventSource requires Content-Type: text/event-stream and fails the connection permanently on anything else, with no reconnection, which is the most common first-contact failure with server-sent events.
The framework cannot read the MIME type, so it reads the pattern: a stream permanently refused more than once, having never delivered a message, on the URL the reads use.
One failed connection stays silent, since it could be an outage, and a stream that has ever delivered a message never triggers this.
Point stream: at a real SSE endpoint, or drop 'sse' from refresh: if the source does not push events.
Streaming covers the rung.
Warning severity: dev-mode only, stripped from production builds.
WF-990
A write() rejection reached no handler
A rejection from write() or create() reached no handler.
Rollback and syncError are automatic, so a fire-and-forget call looks complete, and without a handler the only trace is the browser's uncaught-rejection report, whose stack points into the framework rather than at your call.
This warning gives the query, the operation, and the fact that the rollback already ran.
It changes nothing: no handler is attached on your behalf, the rejection still propagates, and an awaited write in try/catch still sees the failure.
Attach .catch() or await the write in try/catch in the same turn as the call, and acknowledge an intentional fire-and-forget with .catch(() => {}).
Writes states the promise contract.
Warning severity: dev-mode only, stripped from production builds.
WF-991
A write has been pending far longer than a request should take
A write that never settles holds its field claims, keeps pendingWrites raised, and makes persistence, validator caching, and engine refetches wait for a drain that never comes, leaving the query permanently stale.
The notice fires once per query when a write passes ten seconds unsettled.
Nothing is aborted and no timeout is imposed, because the transport belongs to the application and only it knows whether the request is still alive.
Make the transport settle both ways, for example with AbortSignal.timeout inside a function to:.
Note that writes never retry on their own, so an explicit second write() is the only retry.
Writes covers the settle discipline.
Warning severity: dev-mode only, stripped from production builds.
WF-992
A persisted row carries a value JSON cannot round-trip
Persistence serializes rows with JSON.stringify, which stores a Date as a string that restores as a string, and a Map or Set as an empty object with its contents gone.
The live session is unaffected, so the retyping appears only after a reload.
Rows parsed from resp.json() are plain JSON already; the shape that hits this is a function from reading IndexedDB or an in-memory model whose rows carry live objects.
The warning identifies the first offending field once per query, and the save still proceeds, since dropping it would trade a visible warning for invisible data loss.
Shape rows to plain JSON in from: or select:, using numbers or ISO strings for timestamps and arrays instead of Maps and Sets, or drop persist: for the query.
Persistence covers what is stored.
Warning severity: dev-mode only, stripped from production builds.
WF-993
A headers origin key differs from a request's origin only in scheme or port
Header defaults are keyed by origin, and origins compare exactly on scheme, host, and port, so a key spelled slightly wrong matches nothing and the credential never ships.
The request is still legal and the server simply never sees the header, which is what makes the mistake hard to spot.
The usual shapes are an http:// key beside https:// queries, an explicit :443 that request URLs never spell, or a local API on a different port than the key names.
The warning fires at the first request whose origin misses the map while matching a declared key's host, naming both sides, once per key.
Spell the key as the exact origin the requests use, or 'self' for the document's own origin.
Headers and Credentials covers the scoping.
Warning severity: dev-mode only, stripped from production builds.
WF-994
A persist save failed and was dropped, along with the stored snapshot
A persist save threw, from storage quota or from a row JSON.stringify cannot encode.
The engine drops the save and removes the snapshot already on disk, because the stored rows no longer match the last confirmed truth and restoring them tomorrow would misrepresent this session.
The next reload starts cold and revalidates identically.
Without this warning the session reads as though persistence works while nothing is being stored, so the first drop is named once per query with the error that caused it.
For quota, persist fewer or smaller queries, since rows serialize in full.
For serialization, find the value JSON cannot carry; WF-992 lists the common ones before they reach this point.
Persistence covers the storage stance.
Warning severity: dev-mode only, stripped from production builds.
WF-995
write() received a second argument it does not take
A second argument to write(item, …) was ignored, since that form takes only the item.
The two forms are write(item), which derives the operation, and write("name", item), which names one.
There is no per-call options argument: the optimistic flags, success callbacks, and cache directives other libraries pass at the call site are declarations here, and to:, body:, and confirmation: decide reconciliation for every call.
If a named operation was intended, the string goes first.
Named once per query.
Declarative Writes covers where each declaration lives.
Warning severity: dev-mode only, stripped from production builds.
WF-996
write() was called with no item
A write carrying no item claims no fields, applies nothing optimistically, and can roll nothing back.
A keyed list rejects such a call outright (WF-969), but a record query legitimately writes keyless items, so write("favorite") with no item flows through and the request departs carrying nothing.
That can be intended, since a pure side-effect operation whose URL resolves from params: has nothing to put in an item.
More often the item was forgotten, and the first sign used to be a downstream warning about fields or the body that misdescribed the real mistake.
This names the call itself, once per query per operation, and changes nothing about the write.
Pass the row being written, or at least its key.
Named Operations shows the call shapes.
Warning severity: dev-mode only, stripped from production builds.
WF-997
A record-shape binding names a field nothing provides
Inside a record-shape query (a data-query element with no <template>), bindings resolve against the single row merged over component state, the same way a data-list template resolves against its item.
A name that appears in neither renders empty, which looks identical to a field the server has not sent yet.
This fires once per element, and only after a row has actually arrived, so a query still loading is never mistaken for a misspelling.
Check the name against the row your endpoint returns; a field the server sends only sometimes wants a fallback in the expression rather than a bare reference.
Member names, object-literal keys, globals, and $store.path references are all excluded, so this does not fire on correct code.
Record Semantics covers what a record subtree can see.
Warning severity: dev-mode only, stripped from production builds.
WF-998
A confirmation: callback threw
The server answered ok, but the query's confirmation: callback threw while shaping the record, so the write rejected and rolled back anyway.
From the outside that is indistinguishable from a server rejection, which is why this warning identifies the function that raised and the operation it was confirming.
The classic cause is confirmation: r => r.json(): the callback receives the parsed response body, not the Response, and the parsed body has no .json().
Return the record to apply (confirmation: body => body, or extract it from an envelope with body => body.item), or declare no confirmation at all for transport-only writes, where an ok response triggers one conditional refetch instead.
The rejection still propagates to write()'s promise and syncError exactly as it would without the warning.
Warning severity: dev-mode only, stripped from production builds.
WF-999
A write succeeded but its response body is not JSON
The server answered ok to a write, and confirmation: is declared, but the response body could not be parsed, so there was nothing to hand the callback and the query refetched instead.
The write itself stands: the status said the server accepted it, and an unreadable body is not a refusal.
An empty body never reaches this warning. 204 No Content is the ordinary answer to a delete, and an empty body simply means there is nothing to apply, which is silent and expected.
This fires for a body that is present and not JSON, which is usually a content-type mistake or an HTML error page returned with a 200.
Have the endpoint answer with JSON or with no content at all, or drop confirmation: from the operation if its body is never useful.
What comes back covers the three things an ok response can mean.
Warning severity: dev-mode only, stripped from production builds; the write stands and the query refetches in every build.
WF-CSP-SYNTAX
Cannot parse expression
The CSP-safe expression parser encountered syntax it cannot parse. Simplify your binding expression or check for syntax errors. The CSP Mode Limitations section lists what parses.
WF-CSP-UNSUPPORTED
Expression uses unsupported syntax
The expression contains a syntax construct not supported by the CSP-safe expression parser. The parser supports literals, identifiers, member access, binary/logical/unary/conditional expressions, array expressions, and function calls. Anything else (arrow functions, template literals, object literals, destructuring, assignment, etc.) triggers this error. Simplify the expression or move the logic into a computed property or component method. The CSP Mode Limitations section lists the unsupported constructs and the computed-property fix.
WF-CSP-SECURITY
Blocked access to restricted API
CSP security policy blocked one of: (1) a blocked global identifier (window, document, eval, Function, fetch, setTimeout, and others); (2) a blocked property access (__proto__, prototype, constructor); or (3) a function call other than external(). In CSP mode, only external() is permitted as a function call in binding expressions. The What CSP Mode Supports section states the rule.
WF-SEC-BLOCKED
Dangerous attribute or URL value blocked
A binding tried to write a value the security layer refuses by design: a javascript: or vbscript: URL, a scriptable data: URI in a URL attribute (raster image formats are allowed), or a blacklisted attribute such as inline event handlers. The write is dropped in every build; the warning fires in dev builds. This is a policy outcome, not an error. If you control the value, use a safe scheme; if the value is user-supplied, the block is doing its job. The Attribute Bindings page's security section lists the blocked set.
WF-SEC-SANITIZER
HTML rendered without a configured sanitizer
A router outlet is rendering HTML with no sanitizer configured. If the HTML can ever include user-supplied content, configure one with wildflower.setHtmlSanitizer() (for example DOMPurify) to prevent XSS. For fully static, author-controlled HTML the notice can be ignored. The HTML Content Binding section shows the sanitizer setup. Warning severity (console.warn, never throws).
WF-EFFECT
Error resolving path in render effect
The render effect system failed to resolve a binding path during a reactive update. The bound property may not exist on the component's state.