solid-start icon indicating copy to clipboard operation
solid-start copied to clipboard

[Bug?]: Cannot set headers after they are sent to the client

Open harishudewa opened this issue 2 months ago • 4 comments

Duplicates

  • [x] I have searched the existing issues

Latest version

  • [x] I have tested the latest version

Current behavior 😯

I'm trying to use query() with createAsync() in one of my page. Like the following,

// routes/(baseLayout)/index.tsx
import { createAsync, query, redirect, RouteDefinition } from "@solidjs/router";
import { Dialog } from "~/components/Dialog";

const getQuote = query(async () => {
  const quote = await fetch("https://zenquotes.io/api/random");
  throw redirect("/auth/signin");
}, "posts");

function DialogTrigger() {
  return <div>Open dialog</div>;
}

export const route = {
  info: {
    breadcrumbs: {
      label: "Home",
      path: "/",
    },
  },
} satisfies RouteDefinition;

export default function Home() {
  const quote = createAsync(() => getQuote());
  return (
    <div>
      {JSON.stringify(quote())}
      <Dialog trigger={DialogTrigger} />
    </div>
  );
}

But when i go to the page i got the following error:

Image

I tried to refresh the page over and over again, but no hope. Seems like this will occurred when we have fetch() and redirect() altogether. I've tried to change the query() code with just fetch() or redirect() and it's working as expected.

Expected behavior 🤔

No error occurred.

Steps to reproduce 🕹

Steps:

  1. Create query() with fetch() and redirect()
  2. Go to the corresponding page
  3. The error will appeared.

Context 🔦

No response

Your environment 🌎

System:
- OS: macOS Tahoe 26.0
- CPU: Apple M3
Binaries:
- Node: v22.15.0
npmPackages:
- "@solidjs/router": "^0.15.4",
- "@solidjs/start": "^1.2.0",
- "solid-js": "^1.9.10",
- "vinxi": "^0.5.8"

harishudewa avatar Dec 02 '25 00:12 harishudewa

I faced this issue before and found this somewhat helpful post https://www.answeroverflow.com/m/1256901524974604308. Basically add {deferStream: true} as second parameter to createAsync().

Here is what is happening

  • The html starts streaming to the client before getQuote() finishes.
  • Then the redirect is thrown which is done via 302 redirect which sets the location header. This is why the error is complaining about headers, because the headers were already sent with the initial streamed response.
  • Adding {deferStream: true} will defer sending a response until after getQuote() finishes so there will only be one response instead of an initial and a second response with the result of getQuote().

My understanding is somewhat shaky so the details might not be 100%. For some reason when I just tried to reproduce the error, the response was always deferred so I never got the error 🤷

zhengkyl avatar Dec 08 '25 23:12 zhengkyl

@brenelz close? this issue can never be fixed without deferStream. this is the nature of streaming

huseeiin avatar Dec 10 '25 07:12 huseeiin

Perhaps need to update the Docs as well. Initially i encounter this issue because following the auth guide in the Docs.

https://docs.solidjs.com/solid-start/advanced/auth#protected-routes

harishudewa avatar Dec 10 '25 07:12 harishudewa

So this can be closed?

brenelz avatar Dec 11 '25 01:12 brenelz

Headers can only be sent before the response body, that's how the HTTP protocol works. If the body(of any file) started streaming already, then headers cannot longer be sent. I suppose we can close this @brenelz

titoBouzout avatar Jan 07 '26 16:01 titoBouzout