Errors
Every error the SDK throws is a ZeroDustError (or a subclass). ZeroDustAgent.sweep(), batchSweep() and sweepAll() do not throw: they return success: false with the message in error.
ZeroDustError
| Member | Notes |
|---|---|
code |
Machine-readable code (see below) |
message |
What went wrong. For API errors, the API's error text. |
details |
Extra context. For API errors, details.rawError is the API's response body. |
statusCode |
HTTP status, when the error came from an API response |
getUserMessage() |
A short message fit to show an end user |
isRetryable() |
true for NETWORK_ERROR, TIMEOUT, RPC_ERROR, SERVICE_UNAVAILABLE, RATE_LIMITED and INTERNAL_ERROR |
toJSON() |
Plain object for logging |
import { ZeroDust, isZeroDustError } from '@zerodust/sdk';
const zerodust = new ZeroDust({ environment: 'mainnet' });
try {
await zerodust.getQuote({
fromChainId: 8453,
toChainId: 8453,
userAddress: '0xWallet',
destination: '0xDestination',
});
} catch (error) {
if (!isZeroDustError(error)) throw error;
switch (error.code) {
case 'BALANCE_TOO_LOW':
case 'INSUFFICIENT_FOR_FEES':
console.log('Nothing worth sweeping on this chain');
break;
default:
console.error(error.code, error.statusCode, error.message);
}
}
Where codes come from
- API errors. When the API answers with an error body,
codeis the API'scodefield as sent. The API uses more codes than theZeroDustErrorCodetype lists (for exampleINVALID_FROM_CHAIN,SPONSOR_UNAVAILABLEorCHAIN_CLOCK_LAG); compareerror.codeas a string. The REST API page lists the codes per endpoint. - Request validation. A parameter that fails the API's schema returns 400 with code
FST_ERR_VALIDATION. - API errors without a code. Some responses have no
code, for example "Quote not found", "Sweep not found" and "Chain not found". From SDK 0.5.0 the code comes from the HTTP status: 404 isNOT_FOUND, 429 isRATE_LIMITED, 401 and 403 areUNAUTHORIZED, 503 isSERVICE_UNAVAILABLE, any other 4xx isINVALID_REQUESTand a 5xx isINTERNAL_ERROR. (Before 0.5.0 they all arrived as a retryableINTERNAL_ERROR.) - Transport. A network failure is a
NetworkError(NETWORK_ERROR) after the configured retries. A 429 is retried within the sameretriesbudget, after theRetry-Aftertime (at most 30 s) or the usual backoff; a 502, 503 or 504 on a GET is retried the same way. A request that exceedstimeoutis aTimeoutError(TIMEOUT) and is not retried. A non-JSON error response gets its code from the status as above. - Local validation. Bad input is rejected before any request: an invalid address throws
InvalidAddressError(INVALID_ADDRESS), an invalid chain ID throwsINVALID_CHAIN_ID, a malformed signature or authorization throwsINVALID_SIGNATURE, and a quote or sweep ID that is not a UUID throwsQUOTE_NOT_FOUND. - Local safety checks.
verifySweepQuote(),assertAuthorizationMatches()andassertSignedAuthorization()throwUNSAFE_QUOTE. Nothing has been signed when this happens. See Agent.
Codes in ZeroDustErrorCode
| Code | Meaning | Retryable |
|---|---|---|
BALANCE_TOO_LOW |
The balance is 0 | No |
INSUFFICIENT_FOR_FEES |
The balance does not cover the fee reserve | No |
QUOTE_EXPIRED |
The quote's deadline passed; get a new quote | No |
QUOTE_NOT_FOUND |
Unknown quote, or the ID is not a UUID | No |
SIGNATURE_REJECTED |
The signer refused to sign | No |
INVALID_ADDRESS |
Not a valid address | No |
INVALID_CHAIN_ID |
Not a positive integer chain ID | No |
CHAIN_NOT_SUPPORTED |
Chain not supported, or the agent has no RPC for it | No |
NOT_FOUND |
The API has no such quote, sweep or chain (404) | No |
INVALID_REQUEST |
The API rejected the request (a 4xx without a more specific code) | No |
UNAUTHORIZED |
Missing or invalid API key (401, 403) | No |
CHAIN_PAUSED |
ZeroDust paused sweeps from this chain for now | No |
SOURCE_CHAIN_DISABLED |
No bridge currently accepts this source chain | No |
DEST_CHAIN_DISABLED |
No bridge currently delivers to this destination chain | No |
BRIDGE_UNAVAILABLE |
No bridge route right now | No |
CONTRACT_NOT_DEPLOYED |
No ZeroDust contract on this chain | No |
INVALID_SIGNATURE |
The SweepIntent signature does not verify |
No |
EIP7702_INVALID_SIGNATURE |
The delegation authorization does not verify | No |
CHAIN_ID_MISMATCH |
The authorization is for another chain | No |
NONCE_MISMATCH |
The signed delegation nonce differs from the quote's authNonce |
No |
MISSING_CALL_DATA |
A cross-chain quote has no route calldata | No |
UNSAFE_QUOTE |
The quote failed a local safety check; nothing was signed | No |
NETWORK_ERROR |
The request could not be sent or answered | Yes |
TIMEOUT |
The request or waitForSweep() timed out |
Yes |
RPC_ERROR |
A chain RPC failed | Yes |
SERVICE_UNAVAILABLE |
The service is temporarily unavailable | Yes |
RATE_LIMITED |
Too many requests (429), after the SDK's own retries | Yes |
INTERNAL_ERROR |
Any other error, including a 5xx without a code | Yes |
isRetryable() only looks at the code. A retry that needs a new quote (for example after QUOTE_EXPIRED or NONCE_MISMATCH) must start again from getQuote().
Subclasses
NetworkError, TimeoutError and InvalidAddressError are thrown by the SDK. BalanceTooLowError, QuoteExpiredError, ChainNotSupportedError, SignatureError and BridgeError are exported for your own use, but API errors arrive as plain ZeroDustError with the matching code. Branch on error.code, not on instanceof.
Helpers
isZeroDustError(error): type guard.wrapError(error, context?): turns any thrown value into aZeroDustError.createErrorFromResponse(statusCode, body): builds aZeroDustErrorfrom an API error body{ error, code? }.