twentyhq/twenty · critical · RestApiClientError

Global `fetch` function is not available, pass a fetch imple

Error message

Global `fetch` function is not available, pass a fetch implementation to `RestApiClient`.

What it means

Thrown by RestApiClient.sendRequest (rest/index.ts:272-276) as a RestApiClientError when this.fetchImplementation is null. The constructor (line 106) sets fetchImplementation to options.fetch ?? globalThis.fetch ?? null, so any runtime without a global fetch that did not pass `fetch` will hit this on the first request.

Source

Thrown at packages/twenty-client-sdk/src/rest/index.ts:273

          return null;
        })
        .finally(() => {
          this.refreshAccessTokenPromise = null;
        });
    }

    return this.refreshAccessTokenPromise;
  }

  private sendRequest(
    url: string,
    method: string,
    body: unknown,
    token: string,
    requestOptions?: RestApiRequestOptions,
  ): Promise<Response> {
    if (!isDefined(this.fetchImplementation)) {
      throw new RestApiClientError(
        'Global `fetch` function is not available, pass a fetch implementation to `RestApiClient`.',
      );
    }

    const requestHeaders = new Headers(this.defaultHeaders);

    if (isDefined(requestOptions?.headers)) {
      new Headers(requestOptions.headers).forEach((value, key) =>
        requestHeaders.set(key, value),
      );
    }

    const isFormDataBody =
      typeof FormData !== 'undefined' && body instanceof FormData;
    const shouldSerializeBody =
      isDefined(body) && !isFormDataBody && typeof body !== 'string';

    if (isFormDataBody) {

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Pass `fetch` explicitly: `new RestApiClient({ baseUrl, token, fetch: nodeFetch })`.
  2. Upgrade to Node.js 18+ which ships global fetch.
  3. In tests, polyfill globalThis.fetch before constructing the client.
  4. Confirm the polyfill import order runs before instantiation.

Example fix

// before
const client = new RestApiClient({ baseUrl, token });
// after
import fetch from 'node-fetch';
const client = new RestApiClient({ baseUrl, token, fetch });
Defensive patterns

Strategy: validation

Validate before calling

const fetchImpl =
  typeof globalThis.fetch === 'function'
    ? globalThis.fetch
    : (await import('node-fetch')).default;
const client = new RestApiClient({ baseUrl, token, fetch: fetchImpl });

Type guard

const hasGlobalFetch = (): boolean => typeof globalThis.fetch === 'function';

Try / catch

try {
  await client.get('/rest/objects/contact');
} catch (err) {
  if (err instanceof RestApiClientError && err.message.includes('Global `fetch` function is not available')) {
    // pass a fetch polyfill to RestApiClient
  }
}

Prevention

When it happens

Trigger: Using RestApiClient in a runtime that lacks globalThis.fetch (Node < 18, restricted sandboxes) without passing a `fetch` option. The guard fires inside sendRequest on every HTTP call.

Common situations: Node 16/17 deployments; test environments without fetch polyfill; SSR in tooling that strips the global; bundled code where fetch was tree-shaken; React Native without a compatible fetch.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/eb5846b8829c1754. Report an issue: GitHub.