twentyhq/twenty · error · Error

${caller}() failed: HTTP ${response.status} ${response.statu

Error message

${caller}() failed: HTTP ${response.status} ${response.statusText}

What it means

Thrown by postGraphqlRequest when the HTTP response from the Twenty metadata endpoint has a non-2xx status code. This means the transport-level request failed before GraphQL processing — the server rejected the request at the HTTP layer. The status code and status text are included for diagnosis.

Source

Thrown at packages/twenty-sdk/src/sdk/logic-function/utils/post-graphql-request.util.ts:35

  if (!apiUrl || !accessToken) {
    throw new Error(
      `${caller}() requires the app runtime env vars ` +
        `${DEFAULT_API_URL_NAME} and ${DEFAULT_APP_ACCESS_TOKEN_NAME}.`,
    );
  }

  const response = await fetch(`${apiUrl}/metadata`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${accessToken}`,
    },
    body: JSON.stringify({ query, variables }),
  });

  if (!response.ok) {
    throw new Error(
      `${caller}() failed: HTTP ${response.status} ${response.statusText}`,
    );
  }

  const body = (await response.json()) as {
    data?: TData;
    errors?: { message: string }[];
  };

  if (body.errors && body.errors.length > 0) {
    throw new Error(
      `${caller}() failed: ${body.errors.map((error) => error.message).join(', ')}`,
    );
  }

  if (!body.data) {
    throw new Error(`${caller}() failed: response contained no data.`);
  }

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. If status is 401: refresh the access token via the SDK CLI or token refresh flow, then retry.
  2. If status is 404: verify TWENTY_API_URL is correct and the /metadata endpoint exists on that server.
  3. If status is 500/502/503: the server is down — retry with exponential backoff.
  4. If status is 429: you are being rate limited — reduce request frequency and retry after a delay.
  5. Check for network/proxy issues if the status text indicates a connection problem.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const data = await postGraphqlRequest({ query, variables, caller: 'myAction' });
} catch (error) {
  if (error instanceof Error && error.message.includes('HTTP')) {
    const status = error.message.match(/HTTP (\d+)/)?.[1];
    if (status === '401') await refreshTokenAndRetry();
    else if (status?.startsWith('5')) await retryWithBackoff();
    else throw error;
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: The fetch to {apiUrl}/metadata returns a non-ok status: 401 (token expired/invalid), 403 (forbidden), 404 (wrong URL/path), 500 (server error), 502/503 (gateway/service unavailable). This is distinct from GraphQL-level errors (error 98) which come back as 200 with an errors array.

Common situations: The app access token expired and needs refreshing. The TWENTY_API_URL points to the wrong path (e.g. missing /metadata suffix is handled by code, but wrong base URL). The Twenty server is temporarily down. CORS or network proxy issues in browser environments. Rate limiting returns 429.

Related errors


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