Skip to content

Streaming server functions return empty response body with @cloudflare/vite-plugin #6045

@pdlug

Description

@pdlug

Which project does this relate to?

Start

Describe the bug

When using @cloudflare/vite-plugin with TanStack Start, streaming server functions (async generators) return empty response bodies in local development. The server executes correctly and yields values, response headers are correct, but the body is empty.

Your Example Website or App

code in example, needs cloudflare local

Steps to Reproduce the Bug or Issue

  1. Create a TanStack Start project with @cloudflare/vite-plugin
  2. Add a streaming server function using async generator
  3. Run pnpm dev
  4. Click the test button
  5. Observe error: "Stream ended before first object"

vite.config.ts

import { cloudflare } from "@cloudflare/vite-plugin";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import viteReact from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
  server: { port: 3000 },
  plugins: [
    tanstackStart(),
    viteReact(),
    cloudflare({ viteEnvironment: { name: "ssr" } }),
  ],
});

src/routes/index.tsx

  import { createFileRoute } from "@tanstack/react-router";
  import { createServerFn } from "@tanstack/react-start";
  import { useState } from "react";

  const testStream = createServerFn().handler(async function* () {
    console.log("[server] Starting stream");
    yield { count: 1 };
    console.log("[server] Yielded 1");
    yield { count: 2 };
    console.log("[server] Yielded 2");
  });

  export const Route = createFileRoute("/")({
    component: Home,
  });

  function Home() {
    const [result, setResult] = useState("");

    const runTest = async () => {
      setResult("Starting...");
      try {
        for await (const item of await testStream()) {
          setResult((prev) => prev + ` ${item.count}`);
        }
        setResult((prev) => prev + " Done!");
      } catch (error) {
        setResult(`Error: ${error instanceof Error ? error.message : "Unknown"}`);
      }
    };

    return (
      <div>
        <button onClick={() => void runTest()}>Test Stream</button>
        <p>{result}</p>
      </div>
    );
  }

Expected behavior

The client should receive the yielded values { count: 1 } and { count: 2 }.

Actual behavior:

  • Terminal shows server executing correctly:
    [server] Starting stream
    [server] Yielded 1
    [server] Yielded 2
    
  • Client throws: Error: Stream ended before first object
  • curl shows empty body:
    < HTTP/1.1 200 OK
    < content-type: application/x-ndjson
    < transfer-encoding: chunked
    < x-tss-serialized: true
    <
    * Connection #0 to host localhost left intact
    (empty body)
    

Screenshots or Videos

No response

Platform

  • Router / Start Version: 1.140.0
  • OS: macOS
  • Browser: Chrome
  • Browser Version: 144.0.0.0
  • Bundler: Vite
  • Bundler Version: 6.x
  • Additional: @cloudflare/vite-plugin 1.17.0

Additional context

No response

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