Skip to content

Hydration mismatch when a client-only sibling precedes a suspending route in a top-level fragment #3010

Description

@birkskyum

Describe the bug

A top-level fragment containing a client-only component followed by a route subtree that suspends produces a hydration mismatch. The initial server render completes, but client hydration cannot find the route's DOM node and the app is replaced by the error boundary.

This is reduced from SolidStart issue solidjs/solid-start#1452. It uses the built-in clientOnly helper plus a plain createResource; TanStack Query is not involved.

const ClientComponent = clientOnly(() => import("./ClientComponent"));

export default function App() {
  return (
    <>
      <ClientComponent />
      <Router root={props => <Suspense>{props.children}</Suspense>}>
        <FileRoutes />
      </Router>
    </>
  );
}

The matching route suspends for one second:

export default function Home() {
  const [data] = createResource(async () => {
    await new Promise(resolve => setTimeout(resolve, 1000));
    return "loaded";
  });
  return <p>{data()}</p>;
}

Reproduction

https://github.com/birkskyum/repro-solid-client-only-suspense-hydration

git clone https://github.com/birkskyum/repro-solid-client-only-suspense-hydration.git
cd repro-solid-client-only-suspense-hydration
pnpm install
pnpm dev

Open http://localhost:4175 and check the browser console.

Actual behavior

Hydration throws and the app is cleared:

Error: Hydration Mismatch. Unable to find DOM nodes for hydration key: 000000110000000001
<p></p>
  at getNextElement (.../solid-js/web/dist/dev.js)
  at Home (src/routes/index.tsx)

Expected behavior

The client-only component should mount, and the route should display loaded after the resource resolves, without a hydration error.

Controls

Both of these prevent the mismatch:

  1. Replace the top-level fragment in src/app.tsx with a real <div> wrapper.
  2. Make the route synchronous instead of reading the suspending resource.

Disabling the SolidStart dev overlay does not change the result; it is disabled in the reproduction.

Versions

  • solid-js@1.9.15
  • @solidjs/start@2.0.0
  • @solidjs/router@1.0.0
  • vite@8.2.1

Downstream report: solidjs/solid-start#1452

In that report this was identified as another variation of the top-level fragment hydration bug, similar to portals: solidjs/solid-start#1452 (comment)

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