Skip to content

[BUG] new Request(request, init) crashes in route handlers with Invalid URL: [object Request] #1144

@ama2369

Description

@ama2369

Bug: CustomRequest crashes with TypeError: Invalid URL: [object Object]

Description

OpenNext replaces globalThis.Request with CustomRequest, which passes input straight through to workerd's native Request via super(input, init).

workerd's Request constructor only accepts a string, URL, or Request instance. If it gets a plain object, it coerces it to a string ("[object Object]"), tries to parse that as a URL, and crashes. Node.js is more lenient and reads .url from plain objects, which is why this is workerd-specific.

Any code that does new Request({ url, method, headers, body }) triggers the crash (e.g. third-party middleware like Clerk).

Reproduction

The bug in two lines (works in Node.js, crashes in workerd):

const obj = { url: "https://example.com", method: "GET", headers: {}, body: null };
new Request(obj); // TypeError: Invalid URL: [object Object]
Full runnable worker

worker.js:

export default {
  async fetch(request) {
    const obj = { url: request.url, method: "GET", headers: {}, body: null };
    return new Response(new Request(obj).url);
  },
};

wrangler.jsonc:

{ "name": "repro", "main": "worker.js", "compatibility_date": "2024-09-23" }
npx wrangler dev && curl http://localhost:8787/
# → TypeError: Invalid URL: [object Object]

Fix

Before calling super(), check what input is. Strings, URLs, and real Request instances pass through directly. For plain objects, extract .url and merge method/headers/body into init so properties aren't lost:

const OriginalRequest = globalThis.Request;
const CustomRequest = class extends OriginalRequest {
  constructor(input: RequestInfo | URL, init?: RequestInit) {
    // ... existing cache/body fixes ...
    if (typeof input === "string" || input instanceof URL || input instanceof OriginalRequest) {
      super(input, init);
    } else {
      const req = input as unknown as Request;
      const merged = {
        method: req.method,
        headers: req.headers,
        body: req.body,
        ...(req.body ? { duplex: "half" as const } : {}),
        ...init,
      };
      super(req.url, merged as RequestInit);
    }
  }
};

Environment

  • @opennextjs/cloudflare: 1.17.0
  • Cloudflare Workers runtime (workerd)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions