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

  1. Provide a handleRequest(request: Request): Response | Promise<Response> function in the context passed to createFetchableDevEnvironment.
  2. Check the spelling — it must be exactly handleRequest, not handle or on_request.
  3. 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

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


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)