Skip to main content
Most SDK errors are a typed TrustwareError. Routing failures, rate limits, and a few validation checks use their own classes or a plain Error, covered below. You can handle errors reactively via the onError callback, imperatively by catching thrown errors in the headless core, or by listening for the error event in the lifecycle events stream.

The TrustwareError class

TrustwareError extends the native Error class with three additional fields: Import it directly from the SDK:

Error codes

The TrustwareErrorCode enum lists the codes a TrustwareError can carry.
INVALID_API_KEY is thrown synchronously during initialization. Make sure to handle it at startup rather than only in your per-transaction error handler.

Handling errors via onError

Pass an onError callback in your TrustwareConfigOptions to receive all errors emitted by the widget and provider. This is the simplest approach for most integrations.
If you want to display a user-friendly message instead of a raw technical error, use error.userMessage when it is defined:
In production, log error.code and error.message to your error tracking service and display error.userMessage to users. This gives you diagnostic detail without exposing internal error strings.

Handling errors with try/catch

When using the headless core API, errors are thrown as exceptions. Wrap core calls in a try/catch block.

Errors that are not TrustwareError

Some SDK rejections are not a TrustwareError, so an instanceof TrustwareError check will not match them. Check the exported classes, such as RouteExpiredError, ReceiptCommitError, and RateLimitError, with instanceof, and a RouteError with isRouteError(). Match by name or by message only for a plain Error that has no exported class.

Destination posthook validation

Trustware.buildRoute() and Trustware.buildDepositAddress() reject a structurally incomplete hooks.postHook before sending the request. fullAmount and amountInputPos are provider dependent. See amount patching. These checks confirm the request is complete. They do not verify that your calldata is correct, that target is a contract, or that the destination call will succeed. The API is authoritative for everything the client cannot check, and rejects a posthook it will not route with a 400 and a message describing the problem. See vault destinations.

Source token approvals

Trustware.sendRouteTransaction() can submit ERC-20 approvals before the route transaction. Four failures can surface from that step. All four are recoverable. Let the user retry rather than treating the deposit as failed.
SDKRPCError is not exported from the package, so identify it by error.name rather than with instanceof.

Route approvals with no usable amount

Trustware.buildRoute() throws a plain Error when a route.execution.approvals entry has an amount that is missing or not a whole number. Requires SDK 1.1.18 or later. Treat it like any other failed build and let the user try again.

Expired routes

Trustware.sendRouteTransaction(), Trustware.sendReviewedRoute(), and sendRouteAsUserOperation() throw RouteExpiredError when the route’s expiresAt has passed. The route transaction was not sent, but approvals that already confirmed stay on chain. Build a new route. On a Solana route, sendReviewedRoute() checks the route it rebuilds right before signing, not the one you reviewed. Requires SDK 1.1.18 or later.
Trustware.buildRoute() and Trustware.buildDepositAddress() throw RouteResponseError when a route response has no valid expiresAt or Date header. Its field says which. See RouteResponseError.

Refused receipts

Trustware.submitReceipt() throws ReceiptCommitError when Trustware refuses the commit. Branch on error.retryable or error.code, never on the message. retryable is true only for the codes that mean “retry shortly”, so a code your SDK version doesn’t know is final. Requires SDK 1.1.18 or later.
Retrying the same commit is safe; see retries. Refusal codes lists every code.

A resolved poll is not a success

Trustware.pollStatus() resolves when the route reaches success, failed, or expired, and when polling times out. A timeout resolves with the last status it saw, which can be pending, submitted, bridging, or a value newer than your SDK version. Always branch on the status. Polling stops at expired from SDK 1.1.18. Earlier versions keep polling an expired intent until the timeout.

Polling an intent that has no receipt yet

Before a receipt is submitted, status resolves with "pending", a stub with no transaction fields, so check status before reading sourceTxHash, toAmountWei, or any other transaction field. pollStatus keeps polling through it. A 404 is different. It means the intent ID is unknown, so the SDK throws out of the poll loop rather than retrying to the timeout. Catch it as a terminal failure. The SDK throws it as an Error named "HttpError" with a numeric status. HttpError is not exported, so check name and status rather than the message.

The RouteError class

When the routing API cannot produce a route, Trustware.buildRoute() and Trustware.buildDepositAddress() throw a RouteError. It extends the native Error class directly (not TrustwareError), so an instanceof TrustwareError check will not match it. message is the API’s one-line summary, as in earlier versions. Requires SDK 1.1.15 or later; through 1.1.13 these methods throw a plain Error. status, code, and the provider codes match the endpoint’s error responses. buildRoute() rejects a malformed address itself with a plain Error, so invalid_address covers what only the API can check, such as a wrong EVM checksum.

Routes whose fees exceed their output

buildRoute() and buildDepositAddress() refuse a route whose fees exceed what it delivers, and sendRouteTransaction() refuses one before the wallet is asked to sign. The RouteError has status 0 and code "fees_exceed_output", with one provider entry carrying the same code. The API runs a similar check and reports a losing route as a fees_exceed_output decline, so branch on the provider code to handle both.
isRouteError() also recognizes a RouteError thrown by another copy of the SDK bundle, so prefer it over instanceof. parseRouteError(value) returns the same facts, plus the minimum amount a provider asked for when one did, or null when the value carries no routing verdict. formatMinimum(minimum) renders that minimum for display.

The RateLimitError class

When your integration hits the API rate limit, the SDK surfaces the 429 as a RateLimitError. It extends the native Error class directly (not TrustwareError), so a single instanceof TrustwareError check will not match it; handle it as a separate case. The SDK has already waited out the limit on the server’s own schedule before throwing, so do not retry straight away. retriesExhausted says which case you are in: false means the wait is known and longer than the SDK will block for, so rateLimitInfo.retryAfter tells the user when to come back; true means the response carried no usable timing at all.
Rate limiting and retry configuration covers the retry behavior, the two retriesExhausted cases, and the monitoring callbacks. The rateLimitInfo property has the following shape: