vitejs/vite · error · TypeError
FetchableDevEnvironment requires a `handleRequest` method…
Error message
FetchableDevEnvironment requires a `handleRequest` method during initialisation.
What it means
Thrown by createFetchableDevEnvironment() when the provided context object has no handleRequest method. A FetchableDevEnvironment models an environment that can be driven by the Fetch API (Request in, Response out), so a request handler is mandatory — the environment has no default behavior for serving requests. Without it, dispatchFetch() would have nothing to call.
Solutions
- Provide a handleRequest(request: Request): Response | Promise<Response> function in the context passed to createFetchableDevEnvironment.
- Check the spelling — it must be exactly handleRequest, not handle or on_request.
- Ensure the handler actually returns a Response (a fetch() result, new Response(...), etc.), not a plain object.
Example fix
// before
createFetchableDevEnvironment('ssr', config, { modulesRunner: runner })
// after
createFetchableDevEnvironment('ssr', config, {
async handleRequest(request: Request): Promise<Response> {
return new Response('ok')
},
}) Defensive patterns
Strategy: validation
Validate before calling
if (typeof context.handleRequest !== 'function') {
throw new Error('context.handleRequest must be a function returning a Response')
}
const env = createFetchableDevEnvironment(name, config, context) Type guard
function hasHandleRequest(c: DevEnvironmentContext): c is FetchableDevEnvironmentContext {
return typeof (c as any).handleRequest === 'function'
} Prevention
- Type the context parameter as FetchableDevEnvironmentContext so TypeScript enforces handleRequest at compile time.
- Reuse a shared factory wrapper that always injects handleRequest.
When it happens
Trigger: Calling createFetchableDevEnvironment(name, config, context) where context.handleRequest is undefined or not a function (e.g. omitted from the context object, or misspelled as handler/handle). The check is a falsy test on context.handleRequest at fetchableEnvironments.ts:21.
Common situations: Building a custom fetch-based dev environment (e.g. for a framework SSR runner like a Cloudflare/Partytown environment) and forgetting to wire the request handler. Migrating from an older DevEnvironment API where handleRequest was optional. Spreading a base context that did not include handleRequest.
Related errors
- Cannot deep clone non-plain object
- Cannot merge config in form of callback
- Config was resolved for a "build", expected a "serve"…
- FetchableDevEnvironment `context.handleRequest` must return…
- FetchableDevEnvironment `dispatchFetch` must receive a…
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/dca8103fbc4e5e73.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/server/environments/fetchableEnvironments.ts:22
import type { Environment } from '../../environment'
export interface FetchableDevEnvironmentContext extends DevEnvironmentContext {
handleRequest(request: Request): Promise<Response> | Response
}
export function createFetchableDevEnvironment(
name: string,
config: ResolvedConfig,
context: FetchableDevEnvironmentContext,
): FetchableDevEnvironment {
if (typeof Request === 'undefined' || typeof Response === 'undefined') {
throw new TypeError(
'FetchableDevEnvironment requires a global `Request` and `Response` object.',
)
}
if (!context.handleRequest) {
throw new TypeError(
'FetchableDevEnvironment requires a `handleRequest` method during initialisation.',
)
}
return new FetchableDevEnvironment(name, config, context)
}
export function isFetchableDevEnvironment(
environment: Environment,
): environment is FetchableDevEnvironment {
return environment instanceof FetchableDevEnvironment
}
class FetchableDevEnvironment extends DevEnvironment {
private _handleRequest: (request: Request) => Promise<Response> | Response
constructor(
name: string,View on GitHub (pinned to b4d66fee14)