RPC error 3 / -32000: execution reverted

Last updated:

At a glance

Error details
PropertyValue
Applies toEthereum, Polygon, BNB Smart Chain, Base and Robinhood Chain
JSON-RPC code3, or -32000 with the same text
OriginThe contract, relayed unchanged
RetryableNo — deterministic for that block
Revert payload0x08c379a0 = Error(string); custom errors use their own selector
Ethereum, Polygon, BSC, BasePassed through as returned
Robinhood ChainPassed through; revert reason readable via debug_traceCall (best-effort)

Cause

A contract stopped execution with REVERT during eth_call, eth_estimateGas or a trace. Nodes report it either as JSON-RPC code 3 or as -32000 with the text 'execution reverted'; both forms reach you unchanged, because a revert is a result about your transaction rather than an upstream fault. When the contract used a require with a message, the error carries a data payload beginning 0x08c379a0 — the ABI selector of Error(string) — and the reason is decodable from it.

Solution

  1. Decode error.data: a payload starting 0x08c379a0 is Error(string) and holds the human-readable reason; custom errors carry their own four-byte selector, which you can match against your ABI.
  2. Re-run the same call through debug_traceCall on a network that publishes it to see where execution stopped, rather than guessing from the message alone.
  3. Check the block you pinned: a call that succeeds at latest and reverts at an older block usually means state, not logic — see header not found for the archive boundary.
  4. Do not retry unchanged. The result is deterministic for that block and state; a retry returns the same revert.

Decode the reason from error.data

The first four bytes of error.data say what kind of revert you got. Everything after them is ABI-encoded arguments, so the reason is usually in the response you already have.

Revert payloads by selector
Starts withMeaningHow to read it
0x08c379a0Error(string), from require or revert with a messageABI-decode one string
0x4e487b71Panic(uint256), from the compiler: overflow, division by zero, out-of-bounds indexDecode the code: 0x11 overflow, 0x12 division by zero, 0x32 array index
Any other four bytesA custom errorMatch the selector against the contract's ABI
Empty, 0xRevert with no dataTrace the call: the data is not in the response
// Error(string): selector, offset word, length word, UTF-8 bytes
const hex = err.data.slice(10);
const length = parseInt(hex.slice(64, 128), 16);
const bytes = hex.slice(128, 128 + length * 2).match(/../g) ?? [];
const reason = new TextDecoder().decode(
  Uint8Array.from(bytes, (b) => parseInt(b, 16)),
);

Common causes, by what the call was doing

An ERC-20 transferFrom that reverts usually lacks an allowance or a balance, and the two look alike until you read the reason. Swaps revert on slippage checks when the price moved between building and running the call. eth_estimateGas reverts for the same reasons, since it has to execute the transaction: an execution reverted from a gas estimate means the transaction would fail, not that gas estimation is broken.

Check the from address too. Many calls behave differently by sender, and an eth_call without from runs as the zero address, which fails access checks that a real sender would pass.

When the same call succeeds and then reverts

eth_call runs against a block you choose. A simulation at latest can pass and the transaction can still revert in a later block, because state moved. To reproduce a historical failure, pin the call to the block before the transaction; that needs archive state for old blocks, so the answer may be header not found instead. Read the transaction receipt to confirm: status: 0x0 means it was mined and reverted, and you paid for the gas used.

Example

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 3,
    "message": "execution reverted",
    "data": "0x08c379a0…"
  }
}

FAQ

Is execution reverted a Triport error?
No. It is the chain's answer to your call, and we hand it back unchanged — including the data payload, which is where the reason lives.
Why is there no reason text?
The contract reverted without a message, or used a custom error. Only a require with a string produces the 0x08c379a0 Error(string) payload; custom errors identify themselves by a four-byte selector you match against your ABI.