From 4633f0a9e5db161d84f2a052af0a2debe4f15f0a Mon Sep 17 00:00:00 2001 From: "Amir H. Hashemi" <87268103+amirhhashemi@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:40:50 +0330 Subject: [PATCH 1/2] Add a note about using `redirect` with server functions --- .../building-your-application/data-fetching.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/routes/solid-start/building-your-application/data-fetching.mdx b/src/routes/solid-start/building-your-application/data-fetching.mdx index 497499b78..b5ae5566f 100644 --- a/src/routes/solid-start/building-your-application/data-fetching.mdx +++ b/src/routes/solid-start/building-your-application/data-fetching.mdx @@ -41,3 +41,19 @@ const getCurrentUserQuery = query(async (id: string) => { In this example, the `getCurrentUserQuery` retrieves the session data, and if an authenticated user exists, it gets their information from the database and returns it. Otherwise, it redirects the user to the login page. All of these operations are performed completely on the server regardless of how the query is called. + +:::caution[Redirects and streaming don't mix] +HTTP redirects work by setting a `3xx` status code on the response. +Once a response has started streaming, its headers (including the status code) are already sent to the client and cannot be changed, even if the stream hasn't finished yet. + +If a server function attempts to redirect after streaming has begun, you'll encounter the common error: + +**"Cannot set headers after they are sent to the client."** + +To avoid this, disable streaming for queries that may perform a redirect by enabling the [`deferStream`](/solid-router/reference/data-apis/create-async#deferstream) option. + +```tsx +const user = createAsync(() => getCurrentUserQuery(), { deferStream: true }); +``` + +::: From 89ee441d506a9c7c6334be3ec398029fe4748e40 Mon Sep 17 00:00:00 2001 From: "Amir H. Hashemi" <87268103+amirhhashemi@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:54:19 +0330 Subject: [PATCH 2/2] update --- .../building-your-application/data-fetching.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/solid-start/building-your-application/data-fetching.mdx b/src/routes/solid-start/building-your-application/data-fetching.mdx index b5ae5566f..49889f528 100644 --- a/src/routes/solid-start/building-your-application/data-fetching.mdx +++ b/src/routes/solid-start/building-your-application/data-fetching.mdx @@ -42,15 +42,15 @@ In this example, the `getCurrentUserQuery` retrieves the session data, and if an Otherwise, it redirects the user to the login page. All of these operations are performed completely on the server regardless of how the query is called. -:::caution[Redirects and streaming don't mix] -HTTP redirects work by setting a `3xx` status code on the response. -Once a response has started streaming, its headers (including the status code) are already sent to the client and cannot be changed, even if the stream hasn't finished yet. +:::caution[Modifying headers after streaming] +Once a response starts streaming, its headers (including the status code and cookies) are immediately sent to the client and **cannot be modified**. -If a server function attempts to redirect after streaming has begun, you'll encounter the common error: +Any server-side operation that changes headers, such as performing a redirect (`3xx` status) or using APIs like `useSession` that modify cookies, must happen **before** streaming begins. +Otherwise, you'll encounter errors like: **"Cannot set headers after they are sent to the client."** -To avoid this, disable streaming for queries that may perform a redirect by enabling the [`deferStream`](/solid-router/reference/data-apis/create-async#deferstream) option. +To avoid this, disable streaming for queries that may modify headers by enabling the [`deferStream`](/solid-router/reference/data-apis/create-async#deferstream) option. ```tsx const user = createAsync(() => getCurrentUserQuery(), { deferStream: true });