Skip to content

fix(client): stop native fetch from throwing Illegal invocation in browsers - #2112

Merged
dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/fetch-illegal-invocation-fix-b1c195
Sep 28, 2026
Merged

dinwwwh merged 1 commit into
middleapi:mainfrom
dinwwwh:claude/fetch-illegal-invocation-fix-b1c195

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Sep 28, 2026

Copy link
Copy Markdown
Member

Passing the browser's native fetch straight to a link, such as fetch: globalThis.fetch or fetch: window.fetch, no longer fails every request with TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation. The transport now calls the custom fetch without a receiver, so RPCLink and OpenAPILink both work with native fetch passed directly.

Fixes

  • The custom fetch option was called as a method on the transport. Browsers reject native fetch when its this is anything other than the global object. Node's fetch does not check this, so existing tests never caught this.
  • Wrapped forms like (url, init) => globalThis.fetch(url, init), which the docs use, already worked and are unaffected.

Testing

  • Headless Chrome against a real oRPC server with the client bundled from source: before the fix, the default fetch worked and both globalThis.fetch and window.fetch threw Illegal invocation. After the fix, all three return the response.
  • New test asserts the custom fetch is called with this set to undefined. It fails with the old this.fetch(...) call and passes with the fix.
  • Client and OpenAPI fetch adapter tests, eslint, and @orpc/client type:check pass.

…owsers

The fetch link transport called the custom `fetch` option as `this.fetch(...)`,
so passing `fetch: globalThis.fetch` or `window.fetch` directly ran the native
fetch with the transport as its receiver, which browsers reject. Call it
without a receiver instead.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Receiver-free custom fetch — FetchLinkTransport.send now hoists this.fetch into a local before calling it, so native browser fetch no longer receives the transport instance as this. In strict-mode ES modules the bare call yields this === undefined, which is the accepted form for global fetch; the default (globalThis.fetch)(...) wrapper was already correct.
  • Regression test — asserts fetch.mock.contexts equals [undefined]. This genuinely pins the bug: the previous this.fetch(...) invocation records the transport instance as context, so the test fails before the fix and passes after.
  • Coverage — @orpc/openapi's OpenAPILink reuses the same FetchLinkTransport, so it inherits the fix; a repo-wide search found no other site that invokes a custom fetch as a method.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@codecov

codecov Bot commented Sep 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pkg-pr-new

pkg-pr-new Bot commented Sep 28, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@2112

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@2112

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@2112

@orpc/client

npm i https://pkg.pr.new/@orpc/client@2112

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@2112

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@2112

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@2112

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@2112

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@2112

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@2112

@orpc/experimental-lock

npm i https://pkg.pr.new/@orpc/experimental-lock@2112

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@2112

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@2112

@orpc/next

npm i https://pkg.pr.new/@orpc/next@2112

@orpc/node

npm i https://pkg.pr.new/@orpc/node@2112

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@2112

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@2112

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@2112

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@2112

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@2112

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@2112

@orpc/server

npm i https://pkg.pr.new/@orpc/server@2112

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@2112

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@2112

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@2112

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@2112

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@2112

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@2112

commit: 7a842c6

@codspeed

codspeed Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/fetch-illegal-invocation-fix-b1c195 (7a842c6) with main (dfa4e1e)

Open in CodSpeed

@dinwwwh
dinwwwh merged commit f75dbd1 into middleapi:main Sep 28, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant