twentyhq/twenty · error · RestApiClientError

Request to ${url} failed with status ${response.status} ${re

Error message

Request to ${url} failed with status ${response.status} ${response.statusText}

What it means

Thrown by RestApiClient.parseResponse (rest/index.ts:328-337) as a RestApiClientError when `response.ok` is false. Unlike the GraphQL path, this includes structured details (status, statusText, url, body) on the error object. The body is JSON.parsed when possible, otherwise kept as raw text.

Source

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

  }

  private async parseResponse<TResponse>(
    response: Response,
    url: string,
  ): Promise<TResponse> {
    const rawBody = await response.text();
    let parsedBody: unknown = undefined;

    if (rawBody.trim().length > 0) {
      try {
        parsedBody = JSON.parse(rawBody);
      } catch {
        parsedBody = rawBody;
      }
    }

    if (!response.ok) {
      throw new RestApiClientError(
        `Request to ${url} failed with status ${response.status} ${response.statusText}`,
        {
          status: response.status,
          statusText: response.statusText,
          url,
          body: parsedBody,
        },
      );
    }

    return parsedBody as TResponse;
  }

  private async execute<TResponse>(
    method: string,
    path: string,
    body: unknown,
    requestOptions?: RestApiRequestOptions,

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Catch RestApiClientError and read `err.status`, `err.body`, and `err.url` for diagnosis.
  2. For 401, refresh the token and retry (or register the host refresh hook).
  3. For 404, verify the path and resource id; for 400, validate the body shape against the API.
  4. For 5xx, check Twenty server logs and retry with backoff.

Example fix

// before
await client.post('/rest/objects/contact', payload);
// after
try {
  await client.post('/rest/objects/contact', payload);
} catch (err) {
  if (err instanceof RestApiClientError) {
    console.error(err.status, err.body);
  }
  throw err;
}
Defensive patterns

Strategy: try-catch

Type guard

const isRestApiClientError = (e: unknown): e is RestApiClientError =>
  e instanceof RestApiClientError;

Try / catch

try {
  const result = await client.post('/rest/objects/contact', payload);
} catch (err) {
  if (err instanceof RestApiClientError) {
    // err.status, err.statusText, err.url, err.body are all available
    if (err.status === 401) await refreshToken();
    else if (err.status === 404) console.error('Not found:', err.url);
    else console.error('Request failed:', err.status, err.body);
  }
  throw err;
}

Prevention

When it happens

Trigger: Any REST method (get/post/put/patch/delete) where the server returns a non-2xx status: 400 for validation, 401 for auth, 403 forbidden, 404 not found, 5xx server error.

Common situations: Wrong path or REST resource id (404); insufficient permissions (403); malformed body (400); expired token (401); server error (500); rate limiting (429).

Related errors


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