SSR produces invalid HTML (Null Byte U+0000)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Which project does this relate to?
Router
Describe the bug
When TanStack Start/Router performs Server-Side Rendering, it produces multiple Null Bytes (U+0000) inside the "$tsr-stream-barrier" script tag of the server-generated HTML.
According to the HTML Living Standard specification, this character is forbidden from appearing in input streams. Specifically, section "13.2.2 Parse errors" lists the "control-character-in-input-stream" error (https://html.spec.whatwg.org/multipage/parsing.html#parse-errors).
It appears that browsers and other clients simply ignore this; however, when using an HTML validator for frontend projects (like we do at our company), this issue appears consistently. When validating ssr-produced HTML with https://validator.w3.org the error Saw U+0000 in stream comes up.
Complete minimal reproducer
https://github.com/TanStack/router/tree/main/examples/react/start-basic
Steps to Reproduce the Bug
- Create any TanStack Start project that uses SSR. This is easily reproducible with the
start-basicexample from this repo. - Clone this example and install dependencies:
https://github.com/TanStack/router/tree/main/examples/react/start-basic - Build the project:
npm run build - Start the server:
node .output/server/index.mjs - Get the SSR-produced HTML:
curl http://localhost:3000/ > index.html - Visit the W3 markup validation service and upload the file. (https://validator.w3.org/#validate_by_upload)
- Observe the error:
Saw U+0000 in stream.
This issue is NOT exclusive to the start-basic example. From my testing, it occurs every time Router/Start performs server-side rendering and includes the "$tsr-stream-barrier" script tag.
Expected behavior
I expect TanStack's SSR feature to abide by HTML standards and not produce HTML validation errors by default when validating SSR-produced HTML on services like https://validator.w3.org/.
Screenshots or Videos
Null Bytes occur in these 5 places. First occurence is after __root__.
Platform
- Router / Start Version: react-router: 1.170.15, react-start: 1.168.24
- OS: Debian Linux
- Browser: Firefox (not relevant to this issue)
- Browser Version: 150.0.1
- Bundler: vite
- Bundler Version: vite 8.0.14
(See the start-basic example)
Additional context
The null bytes seem to appear at five very specific locations in the script tag (as shown in the screenshot). From my testing, this behaviour (of exactly 5) is very consistent, no matter the project or served content.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the examples/react/start-basic example and reproduce the issue with npm run build, node .output/server/index.mjs, and curl. Inspect the generated HTML around the "$tsr-stream-barrier" script tag and validate it; done means SSR output contains no U+0000 characters and no longer triggers the validator error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript, vite
- Domain
- full-stack, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100