{"id":"28f084c3ca936d3b","repo":"vitejs/vite","slug":"fetchabledevenvironment-context-handlerequest-mu","errorCode":null,"errorMessage":"FetchableDevEnvironment `context.handleRequest` must return a `Response` object.","messagePattern":"FetchableDevEnvironment `context\\.handleRequest` must return a `Response` object\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vite/src/node/server/environments/fetchableEnvironments.ts","lineNumber":56,"sourceCode":"\n  constructor(\n    name: string,\n    config: ResolvedConfig,\n    context: FetchableDevEnvironmentContext,\n  ) {\n    super(name, config, context)\n    this._handleRequest = context.handleRequest\n  }\n\n  public async dispatchFetch(request: Request): Promise<Response> {\n    if (!(request instanceof Request)) {\n      throw new TypeError(\n        'FetchableDevEnvironment `dispatchFetch` must receive a `Request` object.',\n      )\n    }\n    const response = await this._handleRequest(request)\n    if (!(response instanceof Response)) {\n      throw new TypeError(\n        'FetchableDevEnvironment `context.handleRequest` must return a `Response` object.',\n      )\n    }\n    return response\n  }\n}\n\nexport type { FetchableDevEnvironment }\n","sourceCodeStart":38,"sourceCodeEnd":65,"githubUrl":"https://github.com/vitejs/vite/blob/89620f09afcfef6b35e7bb8660132ab5b4d0cd3b/packages/vite/src/node/server/environments/fetchableEnvironments.ts#L38-L65","documentation":"After dispatchFetch calls the user-supplied handleRequest at fetchableEnvironments.ts:56, it asserts the returned value is an instance of global Response. A handler that returns a string, a plain object, undefined, or a Response from a different constructor trips this guard, signalling the contract was broken.","triggerScenarios":"handleRequest returns JSON as a string instead of new Response(json); returns void; returns a Response-like object built by a different Response constructor (polyfill vs global); throws and the catch path returns a non-Response.","commonSituations":"SSR adapters that hand-roll response objects; frameworks migrating from express-style (res.send) to Fetch-style without wrapping; multiple Response constructors in the realm; forgotten return in the handler.","solutions":["Ensure handleRequest always returns new Response(...) (or a Response from the same global constructor).","Wrap non-Response return values: return new Response(body, { status, headers }).","If using a Response polyfill, reconcile it with globalThis.Response so instanceof passes."],"exampleFix":"// before\nhandleRequest: async (req) => { return JSON.stringify(data) }\n\n// after\nhandleRequest: async (req) =>\n  new Response(JSON.stringify(data), {\n    headers: { 'content-type': 'application/json' },\n  })","handlingStrategy":"type-guard","validationCode":"function assertResponse(value: unknown) {\n  if (!(value instanceof Response)) {\n    throw new TypeError('handleRequest must return a global Response instance')\n  }\n}","typeGuard":"function isResponse(value: unknown): value is Response {\n  return typeof Response !== 'undefined' && value instanceof Response\n}","tryCatchPattern":null,"preventionTips":["Always return new Response(...) from handleRequest.","Annotate handleRequest's return type as Promise<Response> | Response so the compiler enforces it.","Reconcile any Response polyfill with globalThis.Response to satisfy instanceof."],"tags":["environment","fetch-api","type-guard","validation"],"analyzedSha":"89620f09afcfef6b35e7bb8660132ab5b4d0cd3b","analyzedAt":"2026-08-03T19:28:02.920Z","schemaVersion":2}