| name | tx-doctor |
| description | Explain why an Ethereum, Base, Arbitrum, Optimism or Polygon transaction failed. One-shot. Use when the user pastes a transaction hash and asks what went wrong, says a transaction failed or reverted, asks why a swap, approval, mint, claim or bridge did not work, asks what "execution reverted" or a bare 0x error selector means, or asks whether a failure was their fault. Also use when a user reports losing gas on a transaction that did nothing. Do NOT use for transactions that are still pending and have no receipt, for questions about what a transaction did when it succeeded, or for general contract auditing.
|
tx-doctor
A receipt says a transaction failed. It does not say why — revert data is not
stored on chain. This recovers it by replaying the call against the state of
the block it ran in, then names the cause.
Procedure
- Run
node bin/tx-doctor.mjs <hash> --json. Add --chain <name> when the
user named a chain other than Ethereum; if they named none, run Ethereum and
state that assumption in your answer.
- Read
diagnosis.cause and diagnosis.confidence from the JSON. Form your
answer from those fields. Do not read the raw revert string and reach your
own conclusion.
- Open with
diagnosis.title rephrased in the user's own terms. Put no hex,
no selector and no gas figure in the first sentence.
- State what the transaction was attempting, using
attempted.signature. When
attempted.signature is absent, write that the function could not be
identified — do not infer it from the recipient address or the user's story.
- Give at most three items from
diagnosis.fixes, choosing the ones that fit
what the user described. Do not invent a fix that is not in the array.
- When
confidence is low, write that the reason could not be recovered and
name what would recover it (an archive-capable RPC endpoint). Do not present
a low-confidence cause as the answer.
- When
cause is ordering-dependent, tell the user their inputs were valid
and they lost a race. Do not tell them to change parameters.
- When
cause is contract-panic and panicCode is not 0x11 or 0x12,
tell the user there is nothing they can change and name the protocol as the
party to report it to.
- When
cause is out-of-gas, state that the gas was still charged.
What each cause means for the reader
cause | Whose problem it is | Lead with |
|---|
slippage | The market moved | The protection worked; retry with a fresh quote |
insufficient-allowance | Caller's setup | Approve the spender, then retry |
insufficient-balance | Caller's funds | The balance at execution time, not now |
deadline-expired | Transaction was too slow | It sat in the mempool; resubmit with a higher fee |
access-control | Wrong sender | Which address is permitted |
paused | Protocol admin | Nothing to fix; wait |
reentrancy | Token or routing | A callback token tripped a guard |
ordering-dependent | Nobody's input | They lost a race, not a validation |
out-of-gas | Caller's limit | Raise the limit; the gas was still charged |
contract-panic | Usually the contract | A broken invariant, not rejected input |
custom-error-unknown | Unrecoverable name | The selector cannot be reversed; the ABI would name it |
silent-revert | Ambiguous | Often the wrong chain or an address with no code |
unknown | Not recovered | Say so, and name the endpoint that would answer |
Never
- Never tell the user to check Etherscan for the reason. You have the reason.
- Never construct, sign, or send a replacement transaction.
- Never advise raising slippage further than
diagnosis.fixes already does;
the array's own caution about sandwiching is part of the answer.
- Never state a cause the tool did not report.
Example
Instead of:
Your transaction reverted with 0x08c379a0.... This usually means a require
statement failed. You could try checking on Etherscan for more details, or
increasing your gas limit and slippage to see if that helps.
Do:
The price moved past your slippage tolerance, so the swap was rejected rather
than filled at a worse price — the protection did its job. You were calling
swapExactTokensForTokens, and it used 12% of its gas limit, so gas was not
the issue. Confidence: high.
Retry with a fresh quote. If it keeps failing on a thin pool, splitting into
smaller trades reduces impact — widening slippage a long way is what makes
sandwiching you profitable.
Observable effect
Every answer names a cause and a confidence level taken from the tool's
JSON, and contains no cause the tool did not report. The phrase "check
Etherscan" does not appear.
Deeper detail
Load only when the specific question calls for it:
references/failure-modes.md — how each cause is detected, and where the
detection is wrong
references/recovering-revert-data.md — why revert reasons are not on chain,
and what the replay actually does