Skip to content

[Bug?]: Dev server returns "[object Object]" with nitroV2Plugin on 2.0.0-alpha.2 #2145

@MarekZeman91

Description

@MarekZeman91

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

Running vite dev with the @solidjs/vite-plugin-nitro-2 setup from its README serves the literal string [object Object] (with Content-Type: text/html) for every page request, instead of the rendered HTML.

$ curl -si http://localhost:5173/
HTTP/1.1 200 OK
Content-Type: text/html
Transfer-Encoding: chunked

[object Object]

Root cause

In @solidjs/start/dist/server/handler.js:

if (mode === "async") return await stream;
delete stream.then;                         // happens before the dev-server branch
if (globalThis.USING_SOLID_START_DEV_SERVER)
    return stream;                           // stream is no longer thenable

solid-start-dev-server sets USING_SOLID_START_DEV_SERVER = true because nitroV2Plugin@0.1.0 doesn't install a FetchableDevEnvironment and the SSR env stays runnable. The handler then returns the Solid stream object, but delete stream.then has already removed its thenable interface.

h3 v2's toResponse no longer recognizes the value as awaitable and falls through prepareResponseBody's default case to new FastResponse(streamObject, …)Response then stringifies the body to [object Object].

Expected behavior 🤔

The dev server should return the SSR-rendered HTML for each page route, the same as the mode: "async" path does today.

Suggested fix

Move delete stream.then after the dev-server branch — only the TransformStream path needs .then removed, which matches the intent of the existing comment about Cloudflare Workers:

if (mode === "async") return await stream;
if (globalThis.USING_SOLID_START_DEV_SERVER)
    return stream;
delete stream.then;
const { writable, readable } = new TransformStream();
stream.pipeTo(writable);
return readable;

Steps to reproduce 🕹

Steps:

  1. Scaffold a minimal SolidStart project with @solidjs/start@2.0.0-alpha.2 and the vite.config.ts straight from the @solidjs/vite-plugin-nitro-2 README:

    import { defineConfig } from "vite";
    import { nitroV2Plugin as nitro } from "@solidjs/vite-plugin-nitro-2";
    import { solidStart } from "@solidjs/start/config";
    
    export default defineConfig({
      plugins: [solidStart(), nitro()]
    });
  2. Use the default entry-server.tsx (no mode option passed to createHandler).

  3. Run vite dev (bun dev or npm run dev).

  4. curl -si http://localhost:5173/ — body is [object Object]. Browser shows the same plain text.

Workaround: pass { mode: "async" } to createHandler — returns await stream before the offending delete, so h3 receives the resolved HTML string.

Context 🔦

Following the documented nitroV2Plugin setup makes the dev server unusable: every route renders [object Object] instead of the app, which blocks any SSR development on 2.0.0-alpha.2. The async-mode workaround unblocks development but disables streaming SSR.

Your environment 🌎

System:
  OS: macOS 26.5 (Darwin 25.5.0)
  CPU: arm64 (Apple Silicon)
Binaries:
  Node: v25.5.0
  Bun: 1.3.14
npmPackages:
  @solidjs/start: 2.0.0-alpha.2
  @solidjs/vite-plugin-nitro-2: 0.1.0
  @solidjs/router: 0.16.1
  @solidjs/meta: 0.29.4
  solid-js: 1.9.12
  vite: 8.0.13
  h3: 2.0.1-rc.4 (transitive, from @solidjs/start)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions