Description
Description
As the error type is picked from the first non-success status, 500 Internal Server Error responses might have a completely different schema or have a completely empty body in contrast to a documented 400 Bad Request.
These responses can still contain valuable headers (Request/Correlation id) that can be used for correlating errors between the frontend app and the api.
Proxies can also attach unique IDs (e.g. Cloudflare Cf-Ray) that would be useful to possibly display to the user in order to find requests by screenshots sent to customer service, or log to some logging system.
Currently there seems to be no way of accessing these headers when errors occur.
Related issue: #2151.
Proposal
-
Breaking change:
Return a different error structure with the response and original error.type QueryError = { response?: Response; // Optional as some error can be thrown during the fetch() call so no response is available. originalError: unknown; // The caught error or the error response. }
-
Non-breaking change:
Allow overriding the returned error when creating the query client.This is my preferred proposal as it would allow errors to be normalized before usage. This would be nice to have on the fetch client as well.
export class ErrorResponse extends Error { constructor( message: string, public readonly code?: string, public readonly correlationId?: string, ) { super(message); } } const queryClient = createQueryClient(fetchClient, { transformError: (error: unknown, response?: Response) => { const correlationId = response?.headers.get("cf-ray"); // Handle fetch/json decode errors if (error instanceof Error) { return new ErrorResponse(error.message, "fetch_error", correlationId); } // Handle error responses if ( error !== null && typeof error === "object" && "code" in error && typeof error.code === "string" ) { return new ErrorResponse("Response error", error.code, correlationId); } // Error did not match expected response type return new ErrorResponse("Unexpected error", "unexpected_error", correlationId); } }); const query = queryClient.useQuery(...); if (query.isError) { query.error; // ErrorResponse, inferred from transformError return value. }
Extra
- I’m willing to open a PR (see CONTRIBUTING.md)