twentyhq/twenty · critical · RestApiClientError

Missing API url. Set the `${DEFAULT_API_URL_NAME}` environme

Error message

Missing API url. Set the `${DEFAULT_API_URL_NAME}` environment variable or pass `baseUrl` to `RestApiClient`.

What it means

Thrown by RestApiClient.resolveBaseUrl (rest/index.ts:163-167) as a RestApiClientError when neither `baseUrl` was passed to the constructor nor the `TWENTY_API_URL` environment variable (DEFAULT_API_URL_NAME) is defined/non-empty. It is the entrypoint guard for every REST request, so the first call fails fast.

Source

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

  patch<TResponse = unknown>(
    path: string,
    body?: unknown,
    options?: RestApiRequestOptions,
  ) {
    return this.execute<TResponse>('PATCH', path, body, options);
  }

  delete<TResponse = unknown>(path: string, options?: RestApiRequestOptions) {
    return this.execute<TResponse>('DELETE', path, undefined, options);
  }

  private resolveBaseUrl(): string {
    const baseUrl =
      this.baseUrl ?? getProcessEnvironment()[DEFAULT_API_URL_NAME];

    if (!isDefined(baseUrl) || baseUrl.trim().length === 0) {
      throw new RestApiClientError(
        `Missing API url. Set the \`${DEFAULT_API_URL_NAME}\` environment variable or pass \`baseUrl\` to \`RestApiClient\`.`,
      );
    }

    return baseUrl.replace(/\/+$/, '');
  }

  private resolveFunctionsBaseUrl(): string | undefined {
    const functionsBaseUrl =
      getProcessEnvironment()[DEFAULT_FUNCTIONS_URL_NAME];

    if (!isDefined(functionsBaseUrl) || functionsBaseUrl.trim().length === 0) {
      return undefined;
    }

    return functionsBaseUrl.trim().replace(/\/+$/, '');
  }

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Set the TWENTY_API_URL environment variable to your Twenty instance (e.g. https://app.twenty.com).
  2. Or pass `baseUrl` explicitly: `new RestApiClient({ baseUrl: 'https://app.twenty.com' })`.
  3. If using dotenv, ensure dotenv.config() runs before constructing the client.
  4. Confirm the variable is exposed to the runtime (serverless/Container env).

Example fix

// before
const client = new RestApiClient();
// after
const client = new RestApiClient({ baseUrl: process.env.TWENTY_API_URL! });
Defensive patterns

Strategy: validation

Validate before calling

const baseUrl =
  options?.baseUrl ?? process.env[DEFAULT_API_URL_NAME];
if (!baseUrl || baseUrl.trim().length === 0) {
  throw new Error('Configure TWENTY_API_URL before constructing RestApiClient');
}
const client = new RestApiClient({ baseUrl });

Type guard

const hasBaseUrl = (opts?: RestApiClientOptions): boolean =>
  isDefined(opts?.baseUrl) && opts.baseUrl.trim().length > 0;

Try / catch

try {
  await client.get('/rest/objects/contact');
} catch (err) {
  if (err instanceof RestApiClientError && err.message.includes('Missing API url')) {
    // set TWENTY_API_URL or pass baseUrl
  }
}

Prevention

When it happens

Trigger: Constructing `new RestApiClient()` without a baseUrl and calling any method (get/post/put/patch/delete/request) without TWENTY_API_URL in the environment. resolveBaseUrl runs inside resolveTarget on every request.

Common situations: Forgot to set TWENTY_API_URL in .env; SSR/build environment missing the variable; typo in the env var name; loading the client before dotenv.config() ran; passing an empty/whitespace string as baseUrl.

Related errors


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