> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sundialprotocol.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reject codes

> The 21 codes the Sundial L2 node's rule engine reports when it rejects a transaction, with the rule each one enforces and how to fix it.

`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

| Code | Engine rule | Meaning |
| - | - | - |
| `E_CBOR_DESERIALIZATION` | Decode | The submitted CBOR doesn't decode to a transaction |
| `E_TX_HASH_MISMATCH` | R2 | The hash recomputed from the body differs from the submitted transaction ID |
| `E_UNSUPPORTED_FIELD_NONEMPTY` | R3 | A redeemer, a Plutus V3 script or a script data hash is present. The detail names the field. |
| `E_EMPTY_INPUTS` | R4 | The transaction has no input |
| `E_DUPLICATE_INPUT_IN_TX` | R5 | An input appears twice |
| `E_INVALID_OUTPUT` | R6 | An output has a negative quantity, an unsummable value, or an unparseable address |
| `E_INPUT_NOT_FOUND` | R7, R8b | An input or reference input isn't in the ledger, or a reference input is also spent by the same transaction |
| `E_DOUBLE_SPEND` | R8 | An input is already spent by an accepted transaction |
| `E_DEPENDENCY_CYCLE` | R17 | The transaction is on a dependency cycle within its batch |
| `E_DEPENDS_ON_REJECTED_TX` | R18 | The transaction depends on a rejected transaction |
| `E_INVALID_VALIDITY_INTERVAL_FORMAT` | R9 | The validity interval isn't well-formed |
| `E_VALIDITY_INTERVAL_MISMATCH` | R10 | The current time is outside the validity interval |
| `E_MIN_FEE` | R11 | The fee is below `min_fee_a × size + min_fee_b` |
| `E_VALUE_NOT_PRESERVED` | R12 | Inputs minus fee doesn't equal outputs |
| `E_MISSING_REQUIRED_WITNESS` | R13, R16 | A required signer or a spent input lacks its witness |
| `E_INVALID_SIGNATURE` | R14 | A signature doesn't verify |
| `E_NATIVE_SCRIPT_INVALID` | R15 | A native script doesn't decode or fails evaluation |
| `E_IS_VALID_FALSE_FORBIDDEN` | R19 | `is_valid` is false |
| `E_AUX_DATA_FORBIDDEN` | R20 | Auxiliary data (metadata) is present |
| `E_MINT_FORBIDDEN` | R23 | The `mint` field isn't empty |
| `E_NETWORK_ID_MISMATCH` | R24 | The transaction's network ID differs from the instance's |

## Common fixes

> **E\_INPUT\_NOT\_FOUND**
>
> 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`](https://docs.sundialprotocol.com/api/utxos), not from an L1 provider.

> **E\_MIN\_FEE**
>
> The fee must be at least 44 lovelace per byte of the transaction's CBOR plus 155,381 lovelace. See [Protocol parameters](https://docs.sundialprotocol.com/reference/parameters.md#ledger-parameters).

> **E\_VALIDITY\_INTERVAL\_MISMATCH**
>
> 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.

> **E\_AUX\_DATA\_FORBIDDEN**
>
> The L2 transaction type has no metadata. If you need to record content, put it in an output's inline datum.

> **E\_DEPENDS\_ON\_REJECTED\_TX**
>
> 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:

| Reason | Meaning |
| - | - |
| `malformed_cbor:<message>` | The transaction didn't decode |
| `mempool_insert_failed:<message>` | The insert into the mempool failed |
| `E_DUPLICATE_TX_ID_CONFLICT` | A different CBOR was submitted under a transaction ID that is already present |

`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](https://docs.sundialprotocol.com/l2/fraud-proofs.md#ledger-rules). Two of them, `E_DEPENDENCY_CYCLE` and `E_DEPENDS_ON_REJECTED_TX`, belong to batch execution and have no ledger rule.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.