Diagnostics

A diagnostic is a finding the runtime makes about your code while it runs: a reactive value read where nothing tracks it, a write from inside a computation, an effect that re-runs because of its own write, a wait the screen never acknowledged. Each finding carries a stable code, and every code has a page here that says what you saw, why it fires, and how to fix it.

A development build prints each finding to the console. An observe build delivers the same findings as events on OBSERVE.diagnostics without printing them, and a test captures them with captureArtifact from @solidjs/diagnostics so that expectNoDiagnostics(artifact) fails on a regression. A production build reports nothing.

Severity says what kind of finding it is: error is broken behavior, warn is code that works but is structurally wrong or expensive, and info is advisory, delivered on the diagnostics channel and never printed. Some codes fire only while the attribution engine is enabled, because they measure cost or waiting rather than correctness; their pages say so.


Read a report

One console entry per finding:

[STRICT_READ_UNTRACKED] Reactive value "title" read directly in <TodoRow> will not update. Move it into a tracking scope (JSX, a memo, or an effect's compute function).
in <App> › <TodoList> › <TodoRow>
at http://localhost:5173/src/components/TodoRow.tsx:18:3
[STRICT_READ_UNTRACKED] what it means and how to fix it: https://v2.solidjs.com/reference/solid-js/diagnostics/strict-read-untracked
[STRICT_READ_UNTRACKED] agent repair guide: node_modules/solid-js/skills/reactivity-diagnostics/SKILL.md#strict_read_untracked — https://github.com/solidjs/solid/blob/next/packages/solid/skills/reactivity-diagnostics/SKILL.md#strict_read_untracked
  • The first line is the code in brackets and the message: what the runtime observed and, for most codes, what to change.
  • The in line is the chain of owners from the root down to the scope that produced the finding: components as <Name>, computations by the name option you gave them or effect/computed by default. No in line means the subject has no named owner: a top-level scope, or an unowned primitive, which for the NO_OWNER_* codes is the finding itself. In a captured artifact the same chain is event.ownerPath.
  • The at line is the source location of the innermost located node on that chain, file:line:col relative to the project root, as written by the compiler's sourceNames locations kind (on in development through @solidjs/vite-plugin). In a browser the path is printed under the dev server's origin, so the console links it to the Sources panel; on the server it is the bare path. In a captured artifact it is event.loc.
  • When the finding is about a compiled JSX binding (an attribute, a class, a style, an inserted value), the entry also carries the element it writes as a second console argument: hover it to highlight the element on the page, click it to jump to the Elements panel.
  • The first report of each code ends with a footer: the link to that code's page here, then the path of the repair skill installed with solid-js for an agent working in the repository.

Naming your memos and effects ({ name }) turns the trailing effect in the in line into something you can search for. Debugging reactivity walks through the common cases.


Codes

CodeKindSeverityTrigger
ABANDONED_FLIGHTSresponsivenesswarnOne async source abandoned 3+ flights in 1s, each superseded before landing — the request-per-keystroke signature (attribution enabled)
ACTION_CALLED_IN_OWNED_SCOPEwriteerroraction() invoked from a component body or computation
ASYNC_OUTSIDE_LOADING_BOUNDARYasyncwarnAsync computation outside Loading boundary (non-halting; root mount is deferred)
ASYNC_STORE_SETTERwriteerrorStore setter callback returned a Promise (setters are synchronous transactions)
ASYNC_WATERFALLperfinfo, warn2+/3+ sequential async flights, origin-proven (attribution enabled)
BINDING_SLOT_POSITIONssr, renderwarn, errorBinding-slot value where it cannot bind; data.reason names the position (spread is an error and throws), client reasons orphan/fill-shape
CLEANUP_IN_FORBIDDEN_SCOPElifecycleerroronCleanup inside trackedEffect/onSettled
DYNAMIC_ASYNC_COMPONENTssrerrorAn async dynamic() source landed on a client component function, which cannot serialize for adoption; the memo rejects (observe + dev; rejects in every tier)
EFFECT_RELAY_TEARperfinfo, warnReader ran twice for one root change because an effect relayed it; warn when derivable or repeated (attribution enabled)
EFFECT_WRITES_OWN_SOURCEperfinfo, warnEffect's write provably feeds back into its own inputs; info for multi-effect rings (attribution enabled)
FALLBACK_FLASHresponsivenessinfoA Loading fallback showed for under 150ms — feedback for a wait too short to need it (attribution enabled)
FLUSH_IN_EFFECT_CALLBACKlifecyclewarnflush() from an effect callback (no-op; the drain is already running)
FRAME_MARKER_CORRUPTEDssrerrorFrame slot range missing its end marker on the client — nesting or an HTML rewriter (observe + dev)
GRAPH_GROWTHperfwarnThe live graph and what outlived each navigation climbed at a route's settle on 3 visits to 1.25× — something each visit leaves behind (attribution enabled)
HEAD_TAG_INVALIDheadwarnuseHead registration the render could not honor; data.reason names the rule (dev)
HOT_SCOPE_FANOUTperfwarn5+/50+/500+ scopes hot from one root cause (attribution enabled)
HOT_SCOPE_RERUNSperfwarn120+ re-runs of one scope in 1s (attribution enabled)
HOT_SCOPE_TIMEperfwarn8ms+ self-time in one scope in 1s (attribution enabled)
HUGE_FAN_INgraphwarnOne recompute tracked 2000 sources (always on)
HUGE_FAN_OUTgraphwarnOne change reached 2000 live subscribers (always on), or 250 — fanOut — on a stamped root write (attribution enabled)
IMMUTABLE_UPDATE_IN_STOREperfwarnStore container replaced by a mostly-identical copy (attribution enabled)
INVALID_AFFECTS_TARGETwriteerroraffects() given a key path, or a key on an accessor
INVALID_REFRESH_TARGETwriteerrorrefresh() target is not a source accessor or refreshable store
INVARIANT_VIOLATIONerrorerrorInternal consistency check failed (throws under __TEST__, reported in dev)
LATE_HEADER_WRITEheaderrorResponse header written after the head was sent; dropped (observe + dev; dev throws)
LAZY_ASSET_UNMAPPEDssrwarnlazy() component's client assets could not be resolved for the page (dev)
LOADING_ON_OUTSIDE_HOLDasyncwarn<Loading on> changed but its data is also read outside the boundary and holds the frame: the fallback can never be seen
LONG_HOLDresponsivenessinfo, warnAcknowledged hold whose tail (last input → commit) ran 500ms+/1000ms+ (attribution enabled)
LOWERCASE_EVENT_ATTRIBUTErenderwarnA function was set on a lowercase on* (or on:) attribute, which is not an event handler in 2.0; use onXxx (dev; client)
MISSING_EFFECT_FNlifecycleerrorcreateEffect called without the effect function
NO_OWNER_BOUNDARYlifecyclewarnBoundary created without owner
NO_OWNER_CLEANUPlifecyclewarnonCleanup called without owner
NO_OWNER_EFFECTlifecyclewarnEffect created without reactive owner
OPTIMISTIC_REVERTEDresponsivenessinfoAn optimistic value the screen showed was replaced by a different one — reverted at settle, or superseded by the truth (attribution enabled)
PENDING_ASYNC_FORBIDDEN_SCOPEasyncwarnPending async read in trackedEffect/onSettled
PENDING_ASYNC_UNTRACKED_READasyncerrorReading pending async outside tracking scope
PRELOAD_DESCRIPTOR_INVALIDheadwarnregisterAsset("preload") descriptor broke a field rule; link dropped or field ignored (dev)
PRIMITIVE_IN_EFFECT_CALLBACKlifecycleerrorMemo, effect, or root created inside an effect callback or its cleanup, where there is no ambient owner (throws)
PRIMITIVE_IN_FORBIDDEN_SCOPElifecycleerrorReactive primitive created inside trackedEffect/onSettled
REACTIVE_WRITE_IN_OWNED_SCOPEwriteerrorReactive write/invalidation inside component/computation
REACTIVITY_HALTEDerrorerrorUncaught error escaped every boundary; scheduling stopped (reported, cause to reportError)
REVEAL_IN_RENDER_TO_STRINGssrwarnNested <Reveal> with collapsed/together under renderToString (dev)
RUN_WITH_DISPOSED_OWNERownerwarnrunWithOwner with disposed owner
SERVER_ERROR_SANITIZEDssrerror, infoError replaced with the generic Error on the wire — data.source "server-function" (error) or "ssr" (info); data.error is the original (observe + dev)
SERVER_WRITEwritewarnSignal/store/optimistic setter ran during a server render; inert, will throw (dev; once per category)
SETTLE_WALK_UNINITIALIZED_SOURCElifecycleerrorInternal: settle walk reached a source that never produced a value (reported)
SETTLED_CLEANUP_UNOWNEDlifecycleerroronSettled returned a cleanup in an unowned (out-of-band) scope
SILENT_HOLDresponsivenessinfo, warnWrite held 100ms+/200ms+ by pending async with no on-screen acknowledgement (attribution enabled)
SSR_BOUNDARY_WATERFALLssrinfo, warnA <Loading> boundary needed 3+/4+ render passes — 2+/3+ sequential async waits (dev)
SSR_CLIENT_CONTENT_MASKEDssrwarnClient-only content in a <Loading> surfaced only after a server wait; the server's work was discarded (dev)
SSR_LIVE_HOLE_LATCHEDssrwarnA live hole that shipped its markers was closed by the impurity gate on re-run and stopped updating (dev)
SSR_RENDER_ERROR_CONTAINEDssrerrorServer render error routed by a boundary: data.handling fallback / client / failed (observe + dev)
SSR_STREAM_ABANDONEDssrwarnResponse stream cancelled or sink failed with fragments pending (observe + dev)
SSR_SUBTREE_ABANDONEDssrwarnA failed fragment's pending descendants were discarded (observe + dev)
SSR_UNDECLARED_LIVE_SOURCEssrwarnA document render is still pumping an async iterable in server-component scope 5s in — declare the function live(...) or bound the source (dev)
STACKED_HOLDSresponsivenesswarn3+ interactions were waiting in one hold when it committed — repeats piled behind the same source (attribution enabled)
STRICT_READ_UNTRACKEDstrict-readwarnUntracked reactive read in component/effect body
SYNC_NODE_RECEIVED_ASYNClifecycleerrorsync: true computation returned a Promise / AsyncIterable
UNRECOGNIZED_INSERT_VALUErenderwarnValue at an insert position the renderer cannot render; skipped (dev; server and client)
UNSCOPED_HOLE_ALLOCATED_IDSrenderwarnUnscoped hole was handed a function whose content took ids at a position the other side does not share; keys permute (dev)
UNSTABLE_LIST_IDENTITYperfwarnmapArray/For recreated rows for equivalent items (attribution enabled)
UNSTABLE_MEMO_OUTPUTperfwarnMemo returned a new-but-equivalent container 4+ runs running (attribution enabled)
UNTRACKED_ASYNC_HANDLERresponsivenessinfo, warnHandler awaited 100ms+/200ms+ past its frame with no write before the await and no action(): a dead click no hold could judge (attribution enabled)
UNTRACKED_READ_AFTER_AWAITasyncwarnAsync computation first read a signal/memo/store key after an await; never a dependency (dev; V8 engines only)
WASTED_RECOMPUTEperfwarn80%+ of a scope's 5+ runs in a second produced an unchanged value for 2ms+ of compute — inputs change, result does not (attribution enabled)
WIDE_SCOPE_DEPSperfwarnScope subscribed to 200+ sources (attribution cost checks on)
Last updated: 10/15/26, 10:07 PMEdit this pageReport an issue with this page