Skip to main content
POST /submit only queues a transaction. The node validates it afterwards, and a transaction that fails is rejected with one of the codes below. A rejected transaction never appears in GET /tx.

How validation runs

The rule engine checks each transaction in two phases:
  • Phase A, stateless. Checks that need only the transaction: its hash, its fields, its fee, its signatures.
  • Phase B, stateful. Checks against the ledger: that inputs exist, that nothing is spent twice, that value is preserved.
The engine rule numbers (R2 to R24) are the ones used in the midgard-ts validation code.

Codes

Common fixes

You built the transaction from L1 UTXOs, or from L2 UTXOs that have since been spent. Read spendable outputs from the L2 node with GET /utxos, not from an L1 provider.
The fee must be at least 44 lovelace per byte of the transaction’s CBOR plus 155,381 lovelace. See Protocol parameters.
The L2 uses POSIX timestamps for validity intervals, and the node checks them against the current time when it admits the transaction. Widen the interval or resubmit.
The L2 transaction type has no metadata. If you need to record content, put it in an output’s inline datum.
Your transaction spends the output of another transaction that was rejected. Fix that one first.

Other rejection reasons

The mempool records a rejection as validation_rejected:<code>, with a detail when the engine supplies one. Three more reasons come from the ingestion path: E_UNSPECIFIED labels a rejection for which the engine gave no code.

Mapping to ledger rules

Each code enforces one or more of the protocol’s ledger rules. Two of them, E_DEPENDENCY_CYCLE and E_DEPENDS_ON_REJECTED_TX, belong to batch execution and have no ledger rule.