vitejs/vite · error · TypeError

FetchableDevEnvironment `context.handleRequest` must return…

Error message

FetchableDevEnvironment `context.handleRequest` must return a `Response` object.

What it means

Thrown by FetchableDevEnvironment.dispatchFetch() after invoking the user-supplied handleRequest, when its returned value is not an instance of the global Response class. The environment enforces the Fetch API contract on the way out so callers can safely treat dispatchFetch as returning a real Response.

Solutions

  1. Make handleRequest return the Response object directly (return fetch(...)), not a parsed body.
  2. If you build a response manually, return new Response(body, { status, headers }).
  3. Ensure the Response class your handler uses is the same global Response the environment checks against (avoid mixing fetch polyfills).

Example fix

// before
async handleRequest(req) { return JSON.stringify(await fetchHandler(req)) }
// after
async handleRequest(req) { return fetchHandler(req) /* returns a Response */ }
Defensive patterns

Strategy: type-guard

Validate before calling

const res = await handleRequest(request)
if (!(res instanceof Response)) {
  throw new TypeError('handleRequest must return a Response')
}

Type guard

function isResponse(v: unknown): v is Response {
  return typeof Response !== 'undefined' && v instanceof Response
}

Prevention

When it happens

Trigger: handleRequest returns a plain object ({ status, body }), a string, JSON via res.json(), or a fetch() result from a different Realm/fetch implementation so `response instanceof Response` is false. The check is at fetchableEnvironments.ts:55.

Common situations: A handler that returns a framework-specific response object (e.g. a Next/Hono Response that isn't the global Response), or returns `await res.json()` instead of the Response itself. A handler that forgets to return. Multiple fetch polyfills (undici vs node:fetch vs window.fetch) creating non-identical Response classes.

Related errors


AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11). Data as JSON: /api/errors/28f084c3ca936d3b. Report an issue: GitHub.

Appendix: source

Thrown at packages/vite/src/node/server/environments/fetchableEnvironments.ts:56

  constructor(
    name: string,
    config: ResolvedConfig,
    context: FetchableDevEnvironmentContext,
  ) {
    super(name, config, context)
    this._handleRequest = context.handleRequest
  }

  public async dispatchFetch(request: Request): Promise<Response> {
    if (!(request instanceof Request)) {
      throw new TypeError(
        'FetchableDevEnvironment `dispatchFetch` must receive a `Request` object.',
      )
    }
    const response = await this._handleRequest(request)
    if (!(response instanceof Response)) {
      throw new TypeError(
        'FetchableDevEnvironment `context.handleRequest` must return a `Response` object.',
      )
    }
    return response
  }
}

export type { FetchableDevEnvironment }

View on GitHub (pinned to b4d66fee14)