Skip to content

[Start] Preserve response-context headers in serialized Server Function responses #7914

Description

@6mn12j

Which project does this relate to?

Start

Describe the bug

Headers set through the Server Function response context are lost when TanStack Start creates a serialized Server Function Response.

Minimal example:

import { createServerFn } from "@tanstack/react-start";
import {
  getResponseHeaders,
  setResponseStatus,
} from "@tanstack/react-start/server";

export const failingFn = createServerFn({ method: "GET" }).handler(
  async () => {
    getResponseHeaders().set("x-custom-header", "true");
    setResponseStatus(401);

    throw new Error("Expected error");
  },
);

After calling failingFn from the client, the resulting /_serverFn/... response has status 401 and the serialization headers, but does not contain x-custom-header: true.

Complete minimal reproducer

https://stackblitz.com/github/tanstack/router/tree/main/examples/react/quickstart-file-based?file=src%2Fmain.tsx

Steps to Reproduce the Bug

  1. Open the provided StackBlitz starter project.
  2. Add the Server Function from the bug description.
  3. Call the Server Function from the client.
  4. Inspect the resulting /_serverFn/... request in the browser Network panel.
  5. Observe that the response status is preserved, but the custom response-context header is missing.
  6. The same header loss is also observable in non-streaming serialized responses, streaming/framed responses, and serialized error responses.

Expected behavior

Headers previously added to the Server Function response context should be preserved in the final serialized response.

Framework-owned serialization headers should take precedence, including:

  • Content-Type
  • x-tss-serialized

Headers invalidated by replacing or streaming the response body, such as a stale Content-Length, should be excluded or recalculated as appropriate.

Screenshots or Videos

No response

Platform

  • Router / Start Version: @tanstack/react-start 1.167.50
  • Resolved @tanstack/start-server-core: 1.167.22
  • OS: macOS
  • Browser: Chrome
  • Bundler: Vite

Additional context

In our application, a backend error logger sets x-logged before rethrowing a 401 ApiError. An outer framework logger checks this marker to prevent duplicate logging.

Because the header is lost during TanStack Start serialization, both logging layers emit an entry for the same request. In Datadog, the paired events appear approximately 7–20 ms apart:

  • Backend 401 ApiError
  • TanStack Start Framework-level error

The affected implementation is in server-functions-handler.ts, where new Response objects are created with status and serialization headers but without copying the response-context headers.

Could serialized responses start with a copy of the response-context headers and then apply the framework-owned headers?

Conceptually:

const headers = new Headers(alsResponse.headers);

headers.set("Content-Type", serializedContentType);
headers.set(X_TSS_SERIALIZED, "true");

The implementation may also need to account for:

  • Headers invalidated by replacing or streaming the body
  • Multiple Set-Cookie values
  • Consistent behavior across success, streaming, and error branches

Related issues that appear adjacent but concern request-header propagation or cookie handling:

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