以太坊交易错误详解:每条消息的含义与修复方法

EVM 错误消息解读及修复方法,作者:ChainGate.

以太坊交易错误是节点拒绝或判定你的交易失败时给出的理由。“Nonce too low”表示这个交易编号已经用过了,刷新钱包即可。“Replacement transaction underpriced”表示你的加速或取消没有把费用提得足够高,至少要提高 10%。“Intrinsic gas too low”表示 gas limit 低于交易的基础成本,需要调高(普通转账最低 21,000)。“Insufficient funds for gas * price + value”表示账户余额不够支付金额加上最高手续费,需要补充原生代币。“Execution reverted”表示合约拒绝了这次调用,这是输入的问题,不是费用的问题。

被拒绝的交易都不消耗 gas,因为它根本没有进入区块。会消耗 gas 的是已打包交易上的“out of gas”和“execution reverted”这两种:网络做了工作,工作失败了,手续费照付。

消息很短,讨论它们的论坛帖子很长,而且大多没有答案就结束了。本指南取以太坊节点软件输出的原始字符串,解释每一条在检查什么,告诉你那次失败的尝试有没有花掉你的钱,并分别给出钱包用户和开发者的修复方法。同样的消息也出现在 Base、Arbitrum、Optimism、Polygon、BNB Smart Chain 以及其他所有 EVM 网络上,因为它们共用同一套节点代码。

简要版

  • 错误分两类。交易进入区块之前被拒绝(nonce、费用、余额、gas limit)不花钱;被打包之后失败(out of gas、execution reverted)要付全额手续费。
  • 这些字符串来自 go-ethereum:nonce too low · replacement transaction underpriced · intrinsic gas too low · insufficient funds for gas * price + value检查的都是交易本身,而不是网络。
  • 大多数只需一行修复:刷新钱包、把费用至少提高 10%、增加 gas,或者补充原生代币。
  • dapp 在“estimate gas”阶段就失败,是在告诉你这次合约调用会 revert。改输入参数;提高 gas limit 没有用。

1. 这些错误消息从哪里来?

几乎所有钱包、库和 RPC 提供商都原样转发 go-ethereum 产生的错误文本,它是运行最广泛的以太坊客户端,各 Layer 2 网络的客户端也复用同样的字符串。MetaMask 把它们包进自己的对话框,ethers.js 加上 NONCE_EXPIRED 或 REPLACEMENT_UNDERPRICED 之类的代码,RPC 提供商则以 code 为 -32000 的 JSON-RPC 错误返回。底下的消息都是同一条。

节点会执行两组不同的检查。第一组在收到交易时进行:nonce 对不对,费用能不能接受,gas limit 是否合理,发送方付不付得起。在这里失败的交易会被丢弃,链上不会留下任何记录。第二组在交易于区块内执行时进行:合约代码能否在 gas limit 之内跑完而不 revert。在这里失败的交易仍然会被打包,在区块浏览器上状态显示为 Fail,手续费已经花掉。

知道一个错误属于哪一类,能同时告诉你两件事:你有没有损失钱,以及问题出在你这边(交易)还是合约那边(输入)。

2. 速查表:所有常见错误

以下是原始字符串,按你最可能遇到的顺序排列。措辞取自 go-ethereum 源码;钱包有时会缩短它。

错误消息含义是否扣 gas?修复
nonce too low带这个 nonce 的交易已经确认否刷新钱包;重发前先在区块浏览器上核对
nonce too high还缺一个更低的 nonce,所以这一笔暂时不能执行否补发或清掉缺失的 nonce;本地链重启后重置开发钱包
replacement transaction underpriced与一笔待确认交易 nonce 相同,但费用提得不够否两个费用字段都至少提高 10%
transaction underpriced费用低于节点的最低要求否提高 max fee 和 priority fee
insufficient funds for gas * price + value余额不够支付金额加上 gas limit 乘以 max fee否补充原生代币(ETH、POL、BNB)或减少金额
intrinsic gas too lowgas limit 低于交易的固定基础成本否提高 gas limit;普通转账为 21,000
exceeds block gas limit / transaction gas limit too highgas limit 超过一个区块的容量,或高于 16,777,216 的上限否降低 gas limit
max fee per gas less than block base fee你的 max fee 低于当前 base fee否提高 max fee,或等 base fee 回落
max priority fee per gas higher than max fee per gas小费设得比总费用上限还高否把 priority fee 设为不高于 max fee
already known节点已经有了这笔一模一样的交易否什么都不用做;等它确认
invalid sender无法从签名恢复出发送方,通常是链 ID 不匹配否用 RPC 报告的链 ID 签名
execution reverted合约代码拒绝了这次调用只有被打包时才扣修正输入:授权额度、滑点、余额、截止时间
out of gas执行在区块内超出了 gas limit是提高 gas limit 后重发

3. “nonce too low”是什么意思?

每个账户从零开始给自己的交易编号,每个编号只能用一次。“Nonce too low”表示你刚发的交易带的编号,网络已经为这个账户确认过了。节点把你交易里的 nonce 和账户下一个预期的 nonce 比较,低于它的一律拒绝。

它出现在钱包对下一个 nonce 的认知过期的时候:同一账户在另一个钱包或设备上发过交易,一次加速或取消已经占用了这个编号,或者本地开发链重启后账户计数归零而 MetaMask 还在往上数。在硬件钱包上,一笔交易被签了两次也会出现它。

修复方法是让钱包重新同步。先在区块浏览器上查一下地址:如果你想做的事已经在那个 nonce 下完成了,就不要重发。如果钱包一直给出过期的编号,MetaMask 的“Delete activity and nonce data”(删除活动和 nonce 数据)选项(设置,开发者工具)会清除当前网络的本地计数器。MetaMask 说明此操作不可逆,只影响当前网络,不会动你的余额。在代码里,签名前用 eth_getTransactionCount 配合“pending”标签读取下一个 nonce,而不是自己维护计数器。

4. “nonce too high”是什么意思?

反方向的缺口。交易的 nonce 高于账户下一个预期值,中间出现了空洞:有一个更低的编号还没有确认。节点会把这样的交易放进队列而不执行,有些节点则直接用这条消息拒绝。

典型原因:一批交易中较早的一笔被丢弃了,或者本地链朝另一个方向重置(链重置了,钱包没有,于是钱包向一条期望 nonce 0 的链发送 nonce 40)。补发缺失的 nonce 来填上缺口,或者像上面那样清除钱包的活动数据。

5. “replacement transaction underpriced”是什么意思?

你试图替换一笔待确认交易(加速、取消,或者干脆用同一个 nonce 重发),而新交易比旧交易多付的费用不够。节点只有在费用提高了一个最低百分比时,才会把待确认交易换成另一笔同 nonce 的交易;在 go-ethereum 里这个价格增幅默认是 10%,而且对 max fee 和 priority fee 都适用。

Nonce 没有问题,问题在价格。把两个费用字段都至少提高 10%,基准是那笔待确认交易,而不是当前的网络行情。MetaMask 对相关的“transaction underpriced”对话框给出的指引是 priority fee 至少提高 10%,max fee 至少提高 30%。如果想取消而不是加速,就用同一个 nonce 和提高后的费用向自己的地址发送 0 ETH,做法见MetaMask 的错误指南。无论哪种方式,替代交易都会得到一个新的交易哈希,旧的那笔被丢弃。

6. “transaction underpriced”是什么意思?

没有“replacement”这个词时,这是一次单纯的价格检查:你交易的费用低于节点愿意留在交易池里的水平。节点会设一个最低 gas 价格来挡住垃圾交易,在繁忙时段,钱包估的“低”档费用可能落到这条线之下。同类消息“transaction gas price below minimum”意思相同。

提高 max fee 和 priority fee 后重发。链上没有任何记录,所以也没有卡住的交易需要清理。如果你在某条网络上反复看到它,说明那条网络的最低要求高于你钱包的默认值;gas 追踪器的各网络页面显示当前行情。

7. “insufficient funds for gas * price + value”是什么意思?

发送方的原生代币余额必须覆盖要发送的金额加上最坏情况下的手续费,也就是 gas limit 乘以 max fee per gas。这条规则写在 EIP-1559 里:签名者必须付得起 gas_limit 乘以 max_fee_per_gas,再加上 value。节点按最大值检查,而不是按交易实际会花多少,所以即使最终手续费本来够付,交易也可能过不了这一关。

三种原因覆盖了几乎所有情况。你持有代币但没有原生代币:Base 上的 USDC 需要 ETH 付 gas,Polygon 上的 USDT 需要 POL,BNB Smart Chain 上的任何东西都需要 BNB。你把全部余额都发出去了,没给手续费留下任何余量:先把最高手续费减掉。或者 gas limit 被一次合约调用抬高了,最坏情况远高于真实成本。

修复:补充原生代币,少发一点,或者在 max fee 或 gas limit 有多余余量时把它们调低。相关的“insufficient funds for transfer”表示还没算 gas,单是金额就已经超过余额。

8. Intrinsic gas too low、out of gas 与 gas limit 错误

有四条消息与 gas limit 有关,它们在不同的时刻失败。“Intrinsic gas too low”是打包前的拒绝:每笔交易在运行任何代码之前都有一个固定基础成本,普通转账是 21,000 gas,再加上每字节数据的费用,而你的 gas limit 低于它。ethereum.org 的 gas 文档把标准转账定为 21,000 单位;代币转账或合约调用需要更多。提高上限,或者让钱包或库来估算。

“Out of gas”是打包后的版本。上限覆盖了基础成本,交易被打包了,然后合约代码需要的 gas 超过了上限允许的量。EVM 会回滚所有状态变更,但正如同一份文档所说,为已完成的工作提供的全部 gas 仍会被消耗。手续费没了,交易在区块浏览器上显示为失败。提高上限后重发;钱包通常会在估算值之上加一点余量,就是为了这个。

“Exceeds block gas limit”表示你设的上限比那条网络的整个区块能容纳的还大。“Transaction gas limit too high”更新一些:自 EIP-7825 起,单笔交易申请的 gas 不得超过 16,777,216(2 的 24 次方),超过上限的交易会被拒绝。两者都通过降低上限来修复;正常的交易永远不需要接近这些数字。

9. Max fee 与 priority fee 错误

自 EIP-1559 起,交易带有两个费用字段:max fee per gas(最高费),即你每单位愿意付的上限;以及 max priority fee per gas(优先费),即给验证者的小费。协议在这两者与区块的 base fee(基础费)之间强制执行两条关系,每条都有自己的错误。

“Max fee per gas less than block base fee”:你的 max fee 低于当前 base fee,所以无论给多少小费交易都无法被打包。这常见于在清闲时段签名、base fee 上涨后才广播的交易,以及用硬编码费用构造的交易。提高 max fee,或者等一等:base fee 逐块变动,一旦跌回你的上限以下,交易就重新有效。

“Max priority fee per gas higher than max fee per gas”:小费超过了总上限,规范禁止这样做,因为 base fee 先被扣掉,小费只能来自剩下的部分。把 priority fee 设为不高于 max fee。构造正确的交易,max fee 大致等于 base fee 的两倍加上小费,这样在等待期间给 base fee 留出了上涨的空间。

10. “execution reverted”是什么意思?

你调用的合约主动停止了执行。Solidity 的 require、revert 和 assert 语句最终都会产生这条消息,后面常常跟着合约自己的原因字符串:“ERC20: transfer amount exceeds allowance”“UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT”“Pausable: paused”等等。原因为空时,你只会看到“execution reverted”或原始错误数据。

大多数时候你在发送前就会看到它,因为钱包会先通过 eth_estimateGas 跑一遍这次调用,而模拟 revert 了;MetaMask 随后会报告它无法估算 gas。这是便宜的版本:什么都没有发出去。昂贵的版本是一笔通过了模拟、被打包、然后在链上 revert 的交易,原因是这期间状态变了(兑换价格越过了你的滑点,别人买走了最后一件,截止时间过了)。它在区块浏览器上显示为 Fail,手续费已付。

修复方法从来不是提高 gas limit。读一读原因字符串,然后改输入:先授权代币,放宽滑点或减少金额,确认合约没有暂停,确认你所在的网络就是合约部署的那条。对于已打包的失败交易,区块浏览器的交易页面会显示 revert 原因;Etherscan 指南展示了在哪里找到它。

11. Already known、invalid sender 与 oversized data

“Already known”在任何实际意义上都不算错误。节点已经持有你发的这笔一模一样的交易,通常是因为某个库重试了广播,或者两个钱包推送了同一份签名字节。等原来那笔确认就好。

“Invalid sender”表示节点无法从签名中恢复出有效的签名者。自 EIP-155 起,链 ID 是被签名内容的一部分,所以为链 1 签名却发到链 137 的交易会恢复出乱码,被拒绝。把签名配置里的链 ID 和 RPC 端点报告的值核对一下;链 ID 列表涵盖了这些编号和不匹配的情形。

“Oversized data”表示交易的字节大小超过了节点交易池接受的上限,只会在非常大的合约部署或 calldata 中出现。拆分数据,或者通过工厂合约部署。

12. 失败的交易会消耗 gas 吗?

取决于它在哪里失败。本指南第一类里的所有错误(nonce、underpriced、insufficient funds、intrinsic gas、费用上限、already known、invalid sender、oversized data)都是拒绝:节点丢弃了交易,没有任何区块包含它,所以没有收取手续费,区块浏览器上也找不到任何东西。重发不需要额外花费。

“Out of gas”和已打包的“execution reverted”属于第二类:交易在区块里,状态为 Fail,验证者做了工作,手续费全额支付。ethereum.org 的文档明确写道,无论交易成功还是失败,手续费都要支付。你试图转移的 ETH 或代币都留在原地;损失的只有手续费。

13. 如何在代码中避免这些错误

四个习惯就能让发送服务避开这份清单上的大部分错误:从节点读取 pending nonce 而不是自己维护计数器,向节点获取你所在网络的费用估算,签名前估算 gas 并加上余量,广播前用金额加最坏情况手续费核对余额。ChainGate SDK 在 transfer() 内部把这四件事都做了,并把你必须自己处理的那一种情况以类型化错误的形式暴露出来:

import { ChainGate, importWallet, NotEnoughFundsError } from 'chaingate';

const cg = new ChainGate({ apiKey: process.env.CHAINGATE_API_KEY });
const wallet = importWallet({ phrase: process.env.MNEMONIC });
const eth = cg.connect(cg.networks.ethereum, wallet);

try {
  // Nonce, gas limit and EIP-1559 fees are read from the node for you
  const tx = await eth.transfer(cg.networks.ethereum.amount('0.05'), '0x...');
  tx.setFee(tx.recommendedFees().normal);

  if (!tx.enoughFunds()) {
    // amount + worst-case fee exceeds the balance: nothing is broadcast
    console.log('short by', tx.missingFunds());
    return;
  }

  const sent = await tx.signAndBroadcast();
  console.log(sent.transactionId);
} catch (err) {
  if (err instanceof NotEnoughFundsError) {
    console.error('Not enough ETH for amount + fee');
  }
  throw err;
}

这篇用 JavaScript 发送加密货币的教程展示了以太坊和 UTXO 链的完整流程,而transfer 文档列出了费用档位和 missingFunds 字段,后者准确告诉你原生代币差多少。

14. 接下来看什么

这些错误大多与费用有关,所以下一页该读的是什么是 gas 费,以及 max fee、priority fee 和 base fee 如何组合在一起,然后是gas 追踪器,看各网络此刻的费率。如果一笔交易确实发出去了,而你需要弄清它后来怎么样了,交易哈希指南展示了如何查询。如果你想要一个在以太坊、各 EVM Layer 2 和比特币上统一处理 nonce、费用和余额检查的 TypeScript 库,ChainGate 就是本站背后的 SDK。

常见问题

MetaMask 里的“nonce too low”是什么意思?

MetaMask 试图使用的交易编号已经为这个账户确认过了,通常是因为另一个钱包、设备或一次加速先用掉了它,或者本地链被重置了。先在区块浏览器上查看这个操作是否已经完成,然后清除 MetaMask 在该网络上的活动和 nonce 数据,让它重新同步。

如何修复“replacement transaction underpriced”?

把替代交易的 max fee 和 priority fee 都在被替换交易的基础上至少提高 10%;go-ethereum 默认的最低增幅就是 10%。如果想取消而不是加速,就用同一个 nonce 和更高的费用向自己发送 0 ETH。

“intrinsic gas too low”是什么意思?

交易的 gas limit 低于它的固定基础成本,普通 ETH 转账是 21,000 gas,代币转账和合约调用更多。提高 gas limit,或让钱包估算。交易在打包前就被拒绝了,所以没有收取手续费。

“insufficient funds for gas * price + value”是什么意思?

账户的原生代币余额不够支付发送金额加上 gas limit 乘以 max fee per gas。只持有代币是不够的:gas 在以太坊和 Base 上用 ETH 支付,在 Polygon 上用 POL,在 BNB Smart Chain 上用 BNB。补充原生代币或少发一点。

“execution reverted”会消耗 gas 吗?

只有交易被打包时才会。钱包在估算 gas 时报告它,说明什么都没有发出去,也没有扣费。已打包的交易 revert 时,手续费全额支付,区块浏览器显示状态为 Fail。

我明明设了 gas limit,为什么交易还是以“out of gas”失败?

这个上限高到足以被接受,却不够运行的合约代码使用。EVM 回滚变更并消耗掉提供的全部 gas,所以手续费花掉了。提高上限后重发;用 eth_estimateGas 的估算值加上余量可以避免这种情况。

“max fee per gas less than block base fee”是什么意思?

交易的 max fee 低于当前 base fee,所以没有区块能把它打包。提高 max fee,或者等 base fee 跌到你的上限以下。这常发生在较早用硬编码费用签好的交易上。

被拒绝的交易要花钱吗?

不要。Nonce too low、transaction underpriced、insufficient funds、intrinsic gas too low 之类的拒绝都发生在交易进入区块之前,所以不收手续费,区块浏览器上也不会出现任何东西。只有已打包却耗尽 gas 或 revert 的交易才会花掉手续费。

这些错误在 Base、Arbitrum、Polygon 和 BNB Smart Chain 上也一样吗?

一样。这些网络运行的 EVM 客户端源自同一套代码,所以消息、nonce 规则和费用检查都相同。不同的是金额:gas 用各网络的原生代币支付,最低费用也远低于以太坊主网。

使用 ChainGate 构建

把这些想法落地 —— ChainGate 提供钱包、交易与托管 RPC,一次安装即可覆盖以太坊以及 20 多条其他区块链。