diff --git a/.changeset/lucky-snails-help.md b/.changeset/lucky-snails-help.md new file mode 100644 index 00000000000..1b8269f8d59 --- /dev/null +++ b/.changeset/lucky-snails-help.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': patch +--- + +Fixed a bug where backend API responses where missing error details. This was caused by parsing the errors twice once in the response error handling code and again when initializing the ClerkAPIResponseError. diff --git a/packages/backend/src/api/factory.test.ts b/packages/backend/src/api/factory.test.ts index a7d373569e6..2d403c26aba 100644 --- a/packages/backend/src/api/factory.test.ts +++ b/packages/backend/src/api/factory.test.ts @@ -150,7 +150,14 @@ export default (QUnit: QUnit) => { }); test('executes a failed backend API request and parses the error response', async assert => { - const mockErrorPayload = { code: 'whatever_error', message: 'whatever error', meta: {} }; + const mockErrorPayload = { + code: 'whatever_error', + message: 'whatever error', + long_message: 'some long message', + meta: { + param_name: 'whatever_param', + }, + }; const traceId = 'trace_id_123'; fakeFetch = sinon.stub(runtime, 'fetch'); fakeFetch.onCall(0).returns(jsonNotOk({ errors: [mockErrorPayload], clerk_trace_id: traceId })); @@ -162,6 +169,9 @@ export default (QUnit: QUnit) => { assert.equal(e.clerkError, true); assert.equal(e.status, 422); assert.equal(e.errors[0].code, 'whatever_error'); + assert.equal(e.errors[0].message, 'whatever error'); + assert.equal(e.errors[0].longMessage, 'some long message'); + assert.equal(e.errors[0].meta.paramName, 'whatever_param'); } assert.ok( diff --git a/packages/backend/src/api/request.ts b/packages/backend/src/api/request.ts index 0cadfd69a23..d0b44f08bae 100644 --- a/packages/backend/src/api/request.ts +++ b/packages/backend/src/api/request.ts @@ -51,18 +51,22 @@ type LegacyRequestFunction = (requestOptions: ClerkBackendApiRequestOptions) * TODO: Simply remove this wrapper and the ClerkAPIResponseError before the v5 release. */ const withLegacyReturn = - (cb: any): LegacyRequestFunction => + (cb: (...args: any) => Promise>): LegacyRequestFunction => async (...args) => { - // @ts-ignore - const { data, errors, status, statusText, clerkTraceId } = await cb(...args); - if (errors === null) { - return data; + const response = await cb(...args); + if (response.errors === null) { + return response.data; } else { - throw new ClerkAPIResponseError(statusText || '', { - data: errors, + const { errors, clerkTraceId } = response; + // TODO: To be removed with withLegacyReturn + const { status, statusText } = response as any; + const error = new ClerkAPIResponseError(statusText || '', { + data: [], status: status || '', clerkTraceId, }); + error.errors = errors; + throw error; } };