twentyhq/twenty · error · Error
${response.statusText}: ${response.rawBody}
Error message
${response.statusText}: ${response.rawBody} What it means
Thrown by TwentyClient.assertResponseIsSuccessful (twenty-client-template.ts:375-378) when the GraphQL HTTP response status is outside the 200-2999 range. This runs after token-refresh retry logic, so the error reflects a final, unrecoverable HTTP-level failure. The message combines statusText and the raw (unparsed) response body.
Source
Thrown at packages/twenty-client-sdk/src/generate/twenty-client-template.ts:377
private async resolveHeaders(): Promise<HeadersInit> {
if (typeof this.headers === 'function') {
return (await this.headers()) ?? {};
}
return this.headers ?? {};
}
private shouldRefreshToken(response: GraphqlResponse): boolean {
if (response.status === 401) {
return true;
}
return hasAuthenticationErrorInGraphqlPayload(response.payload);
}
private assertResponseIsSuccessful(response: GraphqlResponse) {
if (response.status < 200 || response.status >= 300) {
throw new Error(`${response.statusText}: ${response.rawBody}`);
}
if (response.payload === null) {
throw new Error('Invalid JSON response');
}
return response.payload;
}
private async requestRefreshedAccessToken(): Promise<string | null> {
const refreshAccessTokenFunction = (
globalThis as {
frontComponentHostCommunicationApi?: {
requestAccessTokenRefresh?: () => Promise<string>;
};
}
).frontComponentHostCommunicationApi?.requestAccessTokenRefresh;
View on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Read the rawBody portion of the message — it contains the server's actual error payload.
- For 401s, register a token refresh hook on globalThis.frontComponentHostCommunicationApi.requestAccessTokenRefresh or supply a fresh token.
- Verify apiUrl correctness and that the Twenty server is up.
- Check CORS configuration if running in a browser (opaque responses get status 0).
Example fix
// before — no refresh hook, 401 surfaces as error
// after — register a refresh hook before constructing the client
(globalThis as any).frontComponentHostCommunicationApi = {
requestAccessTokenRefresh: async () => refreshTokenPair(),
}; Defensive patterns
Strategy: try-catch
Try / catch
try {
const result = await client.someQuery();
} catch (err) {
// message is `${statusText}: ${rawBody}`
const colonIdx = err.message.indexOf(':');
const statusText = err.message.slice(0, colonIdx);
const rawBody = err.message.slice(colonIdx + 2);
if (statusText === 'Unauthorized') {
await refreshAccessToken();
}
} Prevention
- Register a requestAccessTokenRefresh hook for 401 recovery.
- Validate apiUrl before constructing the client.
- Monitor for 5xx via the catch handler and alert.
- Confirm CORS headers when calling cross-origin from a browser.
When it happens
Trigger: Any GraphQL request whose HTTP status is < 200 or >= 300 after the optional 401 refresh-and-retry path. Common codes: 401 (refresh failed or no refresh hook), 403, 404, 500, 502, 503.
Common situations: Expired access token with no frontComponentHostCommunicationApi.requestAccessTokenRefresh hook registered; server-side 500 from a malformed operation; reverse proxy returning 502/504; wrong apiUrl pointing to a non-GraphQL route returning 404; CORS errors producing an opaque 0-status response.
Related errors
- ${res.statusText}: ${await res.text()}
- Invalid JSON response
- ${caller}() failed: HTTP ${response.status} ${response.statu
- Genql batch fetcher returned unexpected result + JSON.strin
- response length did not match query length
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/9be76eb2e5fd292d.
Report an issue: GitHub.