Skip to content

Solid Query: useQuery({ enabled: false }) hangs renderToStringAsync (SSR) on 5.101.0 #10907

Description

@daviduzumeri

Describe the bug

A useQuery with enabled: false never settles its underlying createResource during SSR, so renderToStringAsync (and SolidStart's async/stream SSR) hangs as soon as the disabled query's .data is read during render.

On the server, solid-query forces experimental_prefetchInRender = true (useBaseQuery), so the observer result carries a .promise. For a disabled query that promise never resolves, and the resource fetcher returns it (via hydratableObserverResult) instead of short-circuiting — so the SSR render awaits a promise that can never settle.

Reproduces on @tanstack/solid-query@5.101.0 (latest) with solid-js@1.9.13.

Related, both closed and neither matching this exact symptom (single useQuery, SSR render hang): #6256, #7167.

Your minimal, reproducible example

Standalone Node ESM — no framework needed. solid-js/web resolves to its server build under Node's default node export condition, so isServer === true.

// repro.mjs  ->  node repro.mjs
import { renderToStringAsync, createComponent, Suspense } from 'solid-js/web'
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/solid-query'

const client = new QueryClient()

function Inner() {
  const q = useQuery(() => ({
    queryKey: ['disabled'],
    queryFn: () => Promise.resolve('data'), // never runs (disabled)
    enabled: false,
  }))
  return () => `data=${JSON.stringify(q.data)}` // reading data drives the resource
}

const App = () =>
  createComponent(QueryClientProvider, {
    client,
    get children() {
      return createComponent(Suspense, {
        get children() {
          return createComponent(Inner, {})
        },
      })
    },
  })

// The race timeout is ONLY so the script exits; renderToStringAsync never settles.
const html = await Promise.race([
  renderToStringAsync(() => createComponent(App, {})),
  new Promise((_, r) =>
    setTimeout(() => r(new Error('renderToStringAsync did not settle (5s)')), 5000),
  ),
])
console.log(html)

Steps to reproduce

  1. npm i @tanstack/solid-query@5.101.0 solid-js@1.9.13
  2. node repro.mjs
  3. Observe it never resolves — the 5s race rejects with renderToStringAsync did not settle.

Expected behavior

A disabled query must not suspend SSR; the resource should resolve immediately with the idle state.

Possible fix

Short-circuiting enabled === false in the useBaseQuery resource fetcher — returning the synchronous result with the dangling .promise stripped — fixes it. Verified locally against 5.101.0:

// inside the createResource fetcher, before `return new Promise(...)`
const obs = observer()
if (obs.options.enabled === false) {
  const { promise, ...rest } = hydratableObserverResult(obs.getCurrentQuery(), observerResult)
  return rest
}
  • unpatched: hangs (5s timeout above)
  • with the short-circuit: resolves in ~25ms with the correct idle state

Happy to open a PR if this approach looks right — wanted to confirm the direction first, since it touches the core query path and enabled can also be reactive (this handles the literal false case).

Environment

@tanstack/solid-query@5.101.0, solid-js@1.9.13, Node 24.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions