trpc/trpc · critical · Error
No fetch implementation found
Error message
No fetch implementation found
What it means
The tRPC client needs a `fetch` implementation to perform HTTP requests. getFetch() checks, in order: an explicitly passed `customFetchImpl`, then `window.fetch`, then `globalThis.fetch`. If none of these is a function, the client cannot make HTTP calls and throws. This is a startup/runtime environment check, not a network error.
Source
Thrown at packages/client/src/getFetch.ts:22
const isFunction = (fn: unknown): fn is AnyFn => typeof fn === 'function';
export function getFetch(
customFetchImpl?: FetchEsque | NativeFetchEsque,
): FetchEsque {
if (customFetchImpl) {
return customFetchImpl as FetchEsque;
}
if (typeof window !== 'undefined' && isFunction(window.fetch)) {
return window.fetch as FetchEsque;
}
if (typeof globalThis !== 'undefined' && isFunction(globalThis.fetch)) {
return globalThis.fetch as FetchEsque;
}
throw new Error('No fetch implementation found');
}
View on GitHub (pinned to acff82332d)
Solutions
- Upgrade to Node.js 18+ (or any runtime with a global fetch).
- Pass an explicit fetch to the link via `fetch` option, e.g. `httpBatchLink({ url, fetch })` or `createTRPCClient({ links: [...], fetch })`.
- Install `undici` / `cross-fetch` and set `globalThis.fetch = undici.fetch` before importing the client.
- In tests, configure the test env to provide a fetch (jsdom + `whatwg-fetch`, or vitest's `environment: 'jsdom'` with fetch enabled).
Example fix
// before
import { createTRPCClient, httpBatchLink } from '@trpc/client';
const client = createTRPCClient({ links: [httpBatchLink({ url: '/api/trpc' })] });
// throws on Node 16
// after
import { fetch } from 'undici';
const client = createTRPCClient({
links: [httpBatchLink({ url: '/api/trpc', fetch })],
}); Defensive patterns
Strategy: validation
Validate before calling
// Run before creating the client
function resolveFetch(explicit?: typeof fetch): typeof fetch | undefined {
if (explicit) return explicit;
const g = globalThis as { fetch?: typeof fetch; window?: { fetch?: typeof fetch } };
return g.fetch ?? g.window?.fetch;
}
const fetchImpl = resolveFetch(myOpts.fetch);
if (!fetchImpl) throw new Error('Configure a fetch polyfill for this runtime'); Type guard
const hasFetch = (): fetch is typeof fetch =>
typeof globalThis !== 'undefined' &&
typeof (globalThis as { fetch?: unknown }).fetch === 'function'; Try / catch
try {
const client = createTRPCClient({ links: [httpBatchLink({ url: '/api/trpc', fetch: fetchImpl })] });
} catch (e) {
if (e instanceof Error && e.message === 'No fetch implementation found') {
// install polyfill and retry, or surface a clear env error
}
throw e;
} Prevention
- Always pass `fetch` explicitly to link options in isomorphic code.
- Pin Node >= 18 in package.json `engines` so a global fetch always exists.
- In tests, assert fetch availability in a global setup file.
When it happens
Trigger: Creating a client with httpLink/httpBatchLink/httpBatchStreamLink and issuing any query or mutation inside a runtime that exposes no global `fetch`. Also triggered when constructing the link eagerly resolves the fetcher before any request is sent in such an environment.
Common situations: Running tRPC client on Node.js < 18 (no built-in fetch), Jest/jsdom configs that don't polyfill fetch, old React Native engines, edge runtimes with fetch disabled, or SSR entry points that import the client before the runtime provides fetch.
Related errors
- No WebSocket implementation found - you probably don't want
- Unsupported version: ${version}
- You're trying to use @trpc/server in a non-server environmen
AI-assisted analysis of trpc/trpc@acff82332d (2026-08-12).
Data as JSON: /api/errors/c8a8d5cc913b185f.
Report an issue: GitHub.