diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index 17aa55f014..1269a19922 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -5,7 +5,8 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ## Unreleased ### Fixed -* Update ripple-binary-codec to 2.5.1 to address serialization/deserialization issues in `Issue` serialized type for MPTIssue. +* Update ripple-binary-codec to 2.5.1 to address serialization/deserialization issues in `Issue` serialized type for `MPTIssue`. +* Better faucet error handling ## 4.4.3 (2025-11-07) diff --git a/packages/xrpl/src/Wallet/fundWallet.ts b/packages/xrpl/src/Wallet/fundWallet.ts index e39236883a..57d5503ee8 100644 --- a/packages/xrpl/src/Wallet/fundWallet.ts +++ b/packages/xrpl/src/Wallet/fundWallet.ts @@ -153,12 +153,11 @@ export async function requestFunding( body: JSON.stringify(postBody), }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- it can be anything - const body = await response.json() if ( response.ok && response.headers.get('Content-Type')?.startsWith('application/json') ) { + const body: unknown = await response.json() // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- It's a FaucetWallet const classicAddress = (body as FaucetWallet).account.classicAddress return processSuccessfulResponse( @@ -168,7 +167,7 @@ export async function requestFunding( startingBalance, ) } - return processError(response, body) + return processError(response) } // eslint-disable-next-line max-params -- Only used as a helper function, lines inc due to added balance. @@ -206,16 +205,26 @@ async function processSuccessfulResponse( ) } -async function processError(response: Response, body): Promise { +interface ErrorData { + body?: unknown + contentType?: string + statusCode: number +} + +async function processError(response: Response): Promise { + const errorData: ErrorData = { + contentType: response.headers.get('Content-Type') ?? undefined, + statusCode: response.status, + } + const clone = response.clone() + try { + const body: unknown = await response.json() + errorData.body = body + } catch { + errorData.body = await clone.text() + } return Promise.reject( - new XRPLFaucetError( - `Request failed: ${JSON.stringify({ - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- json response could be anything - body: body ?? {}, - contentType: response.headers.get('Content-Type'), - statusCode: response.status, - })}`, - ), + new XRPLFaucetError(`Request failed: ${JSON.stringify(errorData)}`), ) } diff --git a/packages/xrpl/test/faucet/fundWallet.test.ts b/packages/xrpl/test/faucet/fundWallet.test.ts index 5a8a7b6aeb..839af4ee53 100644 --- a/packages/xrpl/test/faucet/fundWallet.test.ts +++ b/packages/xrpl/test/faucet/fundWallet.test.ts @@ -121,12 +121,13 @@ describe('fundWallet', function () { throw new Error('Error not thrown') } catch (error) { - await api.disconnect() expect(error).toEqual( new XRPLFaucetError( - 'Request failed: {"body":{"error":"Invalid amount","detail":"Must be an integer"},"contentType":"application/json; charset=utf-8","statusCode":400}', + 'Request failed: {"contentType":"application/json; charset=utf-8","statusCode":400,"body":{"error":"Invalid amount","detail":"Must be an integer"}}', ), ) + } finally { + await api.disconnect() } }) })