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
- If status is 401: refresh the access token via the SDK CLI or token refresh flow, then retry.
- If status is 404: verify TWENTY_API_URL is correct and the /metadata endpoint exists on that server.
- If status is 500/502/503: the server is down — retry with exponential backoff.
- If status is 429: you are being rate limited — reduce request frequency and retry after a delay.
- 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
- Implement token refresh logic for 401 responses.
- Use exponential backoff retry for 5xx errors.
- Monitor HTTP error rates to detect server outages or misconfigured URLs.
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
- ${res.statusText}: ${await res.text()}
- ${response.statusText}: ${response.rawBody}
- createCompany did not return an id
- createPerson did not return an id
- createOpportunity did not return an id
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/69ab835e7763592e.
Report an issue: GitHub.