Handle Errors
Network calls fail: a transaction is rejected, an account does not exist, a request is malformed. This guide shows how to read those errors so you can react to them. It builds on Send a Payment.
Prerequisites
- A funded account to submit from. If you need one, see Connect and Fund an Account.
- The examples run on testnet, so they are free and safe to repeat.
Errors are rejected promises
Every SDK call that hits the network returns a promise that rejects on failure,
so wrap calls in try/catch (or use .catch):
try { await horizon.submitTransaction(tx);} catch (error) { // inspect the error (below)}Read a transaction’s result codes
When a submission fails, Horizon explains why with result codes: one for the
transaction and one per operation. A failed submission rejects with a
TransactionFailedError, and its
getResultCodes()
returns both:
import { TransactionFailedError } from "@stellar/stellar-sdk";
try { await horizon.submitTransaction(tx);} catch (error) { if (error instanceof TransactionFailedError) { const { transaction, operations } = error.getResultCodes(); console.error("transaction:", transaction); // e.g. "tx_failed" console.error("operations:", operations); // e.g. ["op_no_destination"] } else { throw error; }}Common codes you will see (full list in Result Codes):
- Transaction-level:
tx_failed(an operation failed),tx_bad_seq(wrong sequence number, often a stale loaded account),tx_insufficient_fee,tx_too_late(the time bound passed). - Operation-level:
op_underfunded(not enough balance),op_no_destination(the destination account does not exist),op_no_trust(the destination has no trustline for the asset),op_low_reserve(would drop below the minimum balance).
Inspect the full error
For debugging, log the whole error body. When Horizon answers with an error
status, the SDK rejects with a
NetworkError, which carries Horizon’s
problem-details
object at response.data with type, title, status, detail, and extras:
import { NetworkError } from "@stellar/stellar-sdk";
try { await horizon.submitTransaction(tx);} catch (error) { console.error( error instanceof NetworkError ? (error.response.data ?? error) : error, );}Catch a missing account
Reads throw typed SDK errors. Loading an account that does not exist rejects with
NotFoundError, so you can branch on it:
import { NotFoundError } from "@stellar/stellar-sdk";
try { await horizon.loadAccount(accountId);} catch (error) { if (error instanceof NotFoundError) { console.error("That account does not exist yet (fund it first)."); } else { throw error; }}NotFoundError is one of the SDK’s network errors; BadRequestError (malformed
request) and BadResponseError are others, all extending NetworkError, and
TransactionFailedError extends BadResponseError.
Put it together
A runnable script that triggers both failures and handles them:
import { Keypair, Horizon, TransactionBuilder, Operation, Asset, Networks, BASE_FEE,} from "@stellar/stellar-sdk";import { TransactionFailedError } from "@stellar/stellar-sdk";import { NotFoundError } from "@stellar/stellar-sdk";
const horizon = new Horizon.Server("https://horizon-testnet.stellar.org");
const sender = Keypair.random();await horizon.friendbot(sender.publicKey()).call();const account = await horizon.loadAccount(sender.publicKey());
// Pay an account that does not exist -> the transaction fails.const tx = new TransactionBuilder(account, { fee: BASE_FEE, networkPassphrase: Networks.TESTNET,}) .addOperation( Operation.payment({ destination: Keypair.random().publicKey(), asset: Asset.native(), amount: "1", }), ) .setTimeout(30) .build();tx.sign(sender);
try { await horizon.submitTransaction(tx);} catch (error) { if (error instanceof TransactionFailedError) { const { transaction, operations } = error.getResultCodes(); console.error("transaction:", transaction); // e.g. "tx_failed" console.error("operations:", operations); // e.g. ["op_no_destination"] } else { throw error; }}
// Loading a non-existent account throws NotFoundError.const accountId = Keypair.random().publicKey();try { await horizon.loadAccount(accountId);} catch (error) { if (error instanceof NotFoundError) { console.error("That account does not exist yet (fund it first)."); } else { throw error; }}With result codes and typed errors, you can tell the difference between a bad request, a missing resource, and a transaction the network rejected, and respond to each.