Skip to content

Dev middleware can return HTML for internal Vite asset requests on LAN/IP access when Sec-Fetch-Dest is missing #4201

@Neonsy

Description

@Neonsy

Environment

  • Nitro: 3.0.1-20260402-182549-a5a3389c
  • Node.js: v24.14.1
  • Vite: 8.0.7
  • OS: Windows
  • Browser: Helium (Chromium-based) 0.10.8.1
  • Package manager: pnpm

Reproduction

Relevant setup:

  • Using Nitro via nitro/vite inside a Vite dev server
  • Public repro currently uses TanStack Start to demonstrate the behavior, but the suspected problem appears to be in Nitro's dev middleware / Vite handoff

https://github.com/Neonsy/tanstack-start-lan-dev-repro

  1. pnpm install
  2. Run pnpm dev:broken
  3. Open http://localhost:3000/feedback/dev-test
  4. Open the LAN/IP URL printed by Vite, for example http://192.168.100.27:3000/feedback/dev-test
  5. On both pages:
    • click the next-missing button
    • answer both required questions
    • type in the optional textarea
  6. Compare behavior

Describe the bug

In dev mode, internal Vite asset/module requests can be handled incorrectly on LAN/IP access when Sec-Fetch-Dest is missing

In the repro:

  • localhost works
  • the same valid page on the LAN/IP URL SSR-renders but client behavior stays stale
  • an internal Vite request returns HTML instead of the expected JavaScript module response

This does not look like app-specific state logic
The same page and route are valid, and the failure only appears when internal dev asset handling differs between localhost and LAN/IP access

Expected:

  • internal Vite module requests should still be delegated correctly even when Sec-Fetch-Dest is missing
  • localhost and LAN/IP access should behave the same in dev mode

Actual:

  • on the failing LAN/IP path, an internal request such as vite/dist/client/env.mjs can return 404 text/html
  • hydration-dependent UI then stops behaving correctly because the expected module response was not served

Additional context

The repro includes two modes:

  • pnpm dev:broken
  • pnpm dev:patched

The patched mode applies a dev-only middleware before Nitro handling that sets:

req.headers["sec-fetch-dest"] = "script"

when the header is missing for obvious internal module requests such as:

  • /@vite/client
  • /@react-refresh
  • /@vite/env
  • /@id/*
  • /src/*.(css|js|ts|tsx|mjs|cjs|mts|cts)
  • /node_modules/* with those extensions

On my machine:

  • broken mode:
    • localhost passes
    • LAN/IP fails
    • vite/dist/client/env.mjs returns 404 text/html on the LAN path
  • patched mode:
    • localhost passes
    • LAN/IP passes
    • the same internal request returns a JavaScript module response

This makes it look like the bug is in the dev middleware routing / handoff decision when Fetch Metadata headers are missing, rather than in application code

Related downstream report:

Note

This issue derived from my issue, placed on the tanstack repo

Logs

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions