TER Result Codes

← Back to Transactors: Understanding the Lifecycle of a Transaction


Introduction

Every transaction in the XRP Ledger produces a result code called a TER (Transaction Engine Result). These codes communicate the outcome of transaction processing—whether it succeeded, failed, or needs to be retried. Understanding TER codes is essential for building applications that correctly handle transaction outcomes and for debugging transaction failures.

The TER code system is defined in include/xrpl/protocol/TER.h and provides a rich taxonomy of outcomes that guide both the consensus process and client applications.


TER Code Categories

TER codes are organized into distinct ranges, each indicating a different category of outcome:

Range
Prefix
Name
Meaning
Fee Charged?

-399 to -300

tel

Local

Local processing error

No

-299 to -200

tem

Malformed

Transaction is malformed

No

-199 to -100

tef

Failure

Transaction failed

No

-99 to -1

ter

Retry

Transaction may succeed later

No

0

tes

Success

Transaction succeeded

Yes

100+

tec

Claim

Transaction failed but fee claimed

Yes


tesSUCCESS (0)

The only success code. The transaction was applied successfully and achieved its intended effect.

Characteristics:

  • Transaction is included in a validated ledger

  • All intended state changes were applied

  • Transaction fee was charged

  • Sequence number was consumed


tem* Codes: Malformed Transactions

Range: -299 to -200

Malformed transactions have structural or format problems that make them permanently invalid. These transactions can never succeed, regardless of ledger state.

Common tem Codes:*

Code
Meaning
Typical Cause

temMALFORMED

Generic malformed

Invalid transaction structure

temBAD_AMOUNT

Invalid amount

Negative, zero, or overflow

temBAD_CURRENCY

Invalid currency

Bad currency code format

temBAD_EXPIRATION

Invalid expiration

Zero or negative expiration

temINVALID_FLAG

Invalid flag

Unknown or conflicting flags

temREDUNDANT

Redundant operation

Self-send, self-trust, etc.

temDISABLED

Feature disabled

Amendment not enabled

Example Usage in Code:

Client Handling: Never retry tem* transactions—they are permanently invalid.


tef* Codes: Failure

Range: -199 to -100

Failure codes indicate that the transaction cannot succeed due to the current ledger state, but the failure is not permanent.

Common tef Codes:*

Code
Meaning
Typical Cause

tefPAST_SEQ

Sequence already used

Transaction already applied or sequence too low

tefMAX_LEDGER

LastLedgerSequence passed

Transaction expired

tefBAD_SIGNATURE

Invalid signature

Wrong key or corrupted signature

tefBAD_AUTH

Authorization failed

Signer not authorized

tefINTERNAL

Internal error

Unexpected state (bug)

tefINVARIANT_FAILED

Invariant check failed

Transaction would violate ledger invariants

Example:

Client Handling: Generally don't retry—the transaction has a fundamental problem.


ter* Codes: Retry

Range: -99 to -1

Retry codes indicate that the transaction could not be applied now but might succeed later if ledger state changes.

Common ter Codes:*

Code
Meaning
What to Do

terPRE_SEQ

Sequence too high

Wait for earlier transaction

terQUEUED

In queue

Wait for queue processing

terINSUF_FEE_B

Fee too low

Increase fee and resubmit

terNO_ACCOUNT

Account doesn't exist

Fund the account first

Client Handling: May retry after conditions change (e.g., earlier transaction applies, fee drops).


tec* Codes: Claimed Cost

Range: 100+

These codes indicate that the transaction was included in a ledger and the fee was charged, but the intended operation did not succeed. The transaction "claims" its cost (fee + sequence) but doesn't achieve its goal.

Common tec Codes:*

Code
Meaning
Typical Cause

tecNO_DST

No destination

Destination account doesn't exist

tecUNFUNDED_PAYMENT

Insufficient funds

Not enough balance for payment

tecINSUFFICIENT_RESERVE

Reserve not met

Can't afford new object

tecFROZEN

Asset frozen

Trust line or global freeze

tecNO_PERMISSION

Not permitted

Account flags prevent operation

tecDST_TAG_NEEDED

Tag required

Destination requires tag

tecEXPIRED

Expired

Object or transaction expired

tecDIR_FULL

Directory full

Too many objects

Example Usage:

Client Handling: Transaction is final—fee was charged, but operation failed. Fix the issue and submit a new transaction.


tel* Codes: Local Errors

Range: -399 to -300

Local errors occur during local processing and are not related to consensus. The transaction is not forwarded to the network.

Client Handling: Address the local issue (fee, network, etc.) and resubmit.


The NotTEC Type

The codebase uses a special type NotTEC for functions that cannot return tec codes:

Why NotTEC exists:

Preflight runs before signature verification. If preflight could return tec codes (which claim fees), an attacker could:

  1. Submit a malformed transaction with a valid account but invalid signature

  2. Have the fee claimed from that account

  3. Drain accounts without proper authorization

By returning NotTEC, preflight ensures no fees can be claimed for unsigned transactions.


Helper Functions

The TER header provides utility functions for checking result categories:


Decision Tree for Choosing Result Codes


Best Practices

  1. Choose the right code: Match the error category to the situation

  2. Use specific codes: Prefer tecNO_DST over generic tecFAILED_PROCESSING

  3. Log with context: Include helpful debug information in logs

  4. Return early: Check cheapest conditions first, return on failure

  5. NotTEC in preflight: Never return tec codes from preflight


Codebase References

File
Description

include/xrpl/protocol/TER.h

TER code definitions and helper functions

src/libxrpl/protocol/TER.cpp

TER string conversion implementation

Last updated