JSON-RPC -32602 Invalid params 会在请求信封格式正确、但 params 值在结构或语义上无法被服务器接受时返回。JSON-RPC 2.0 规范要求 params 必须是数组(位置参数)或对象(按名参数),而以太坊 JSON-RPC 规范则定义了哪些方法使用哪种形式。现实中大多数 -32602 错误来自 hex quantity 格式错误、参数顺序错误,或向只实现位置参数的客户端发送按名对象。本文介绍如何在发送前校验参数个数、编码、地址大小写和区块标签,如何用 curl 逐步定位失败的调用,以及如何用结果表记录你的端点容忍度。
JSON-RPC 2.0 中 -32602 Invalid params 的含义
JSON-RPC 2.0 规范定义了一组固定的错误码,-32602 Invalid params 就是其中之一。当方法存在且请求信封有效,但 params 值在结构或语义上无法被服务器接受时,就会返回该错误。这与方法未找到错误不同,后者表示方法名本身未知。
规范规定 params 必须是数组(位置参数)或对象(按名参数)。只有在方法不接受任何参数时,才允许完全省略 params。向期望位置参数的方法发送 params: {},或向期望按名对象的方法发送 params: [..],在符合规范的服务器上会立即返回 -32602。
以太坊 JSON-RPC 规范在此基础上定义了哪些方法使用位置数组、哪些方法接受按名对象。大多数执行层方法(如 eth_getBalance、eth_call 和 eth_getLogs)使用位置数组。部分客户端还会为某些方法额外接受按名对象,但这并非普遍支持,且因客户端和版本而异。
- params 必须是数组或对象;只有零参数方法才允许省略 params。
- -32602 表示方法已被识别,但参数被拒绝。
- 规范并不要求服务器在错误消息中指明是哪个参数出错。
- 各提供商对按名参数的容忍度有文档说明,且因提供商而异。
位置参数与按名参数,以及客户端容忍度边界
以太坊 JSON-RPC 规范几乎对所有标准方法都使用位置数组。例如 eth_getBalance 接受 [address, blockTag]。如果客户端只实现位置参数,而你发送对象 {"address": "0x...", "blockTag": "latest"},即使方法存在且值正确,也会返回 -32602。
部分客户端(包括某些版本的 Geth 和 Erigon)为方便起见,会对一部分方法接受按名对象。这并非规范保证,且可能随版本变化。一个请求在某个端点上通过,可能在另一次升级后于另一个端点上失败,因此在生产代码中依赖按名参数是有风险的。
下表总结了这一边界。请将“接受按名参数”一列视为有文档说明/因提供商而异,而非固定保证。
- 位置数组是以太坊方法可移植且符合规范的形式。
- 按名对象可能在某些客户端上可用,但并非普遍支持。
- 只实现位置参数的客户端会对按名对象返回 -32602。
- 务必针对你的具体端点和客户端版本进行测试。
// Comparison of params forms for eth_getBalance
// Positional (portable):
{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"],
"id": 1
}
// By-name (may return -32602 on some clients):
{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": {"address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "blockTag": "latest"},
"id": 1
}Hex quantity 与 data 编码:现实中最常见的原因
以太坊 JSON-RPC 规范区分 QUANTITY 和 DATA 两种编码。QUANTITY 值必须以 0x 为前缀,使用尽可能少的十六进制位数,且不能有前导零。DATA 值必须以 0x 为前缀,且长度为偶数。规范要求 0x3e8 的地方写成十进制 1000,是 -32602 的常见原因;像 0x03e8 这样带前导零的 quantity 也一样。
字符串拼接通常是罪魁祸首。用 '0x' + number.toString(16) 构建十六进制字符串在简单情况下可行,但当数字为零(会生成 '0x0',这是合法的)或填充逻辑引入前导零时就会出错。应使用专门的编码器,如 ethers.js 的 hexlify 或 viem 的 toHex,来避免这类错误。
地址大小写也很重要。规范接受小写地址和校验和地址,但部分客户端会拒绝全大写或不符合 EIP-55 校验和的混合大小写地址。使用 ethers.js 的 getAddress 或 viem 的 getAddress 规范化地址,可以避免这一类 -32602。
- QUANTITY:以 0x 为前缀,无前导零,使用最少十六进制位数。
- DATA:以 0x 为前缀,偶数长度十六进制。
- 使用 hexlify / toHex,而不是手动字符串拼接。
- 发送前将地址规范化为小写或有效的 EIP-55 校验和形式。
// Correct encoding with ethers.js v6
import { hexlify, getAddress } from 'ethers';
const blockNumber = 1000;
const quantity = hexlify(blockNumber); // '0x3e8'
const address = getAddress('0x742d35cc6634c0532925a3b844bc454e4438f44e');
// Incorrect: decimal where hex is required
// const badQuantity = 1000; // -32602
// Incorrect: leading zero in quantity
// const badQuantity2 = '0x03e8'; // -32602 on strict clients面向 Node.js 客户端的预检校验函数
在请求离开进程之前校验参数,是避免 -32602 最有效的方法。下面的函数针对一小组常用方法检查参数个数、hex quantity 格式、地址大小写和区块标签有效性。随着你添加方法,扩展 schema 映射即可。
该校验器返回一个错误字符串数组。如果数组为空,请求就可以安全发送。这不能替代服务端校验,但能在消耗一次往返之前捕获大多数客户端侧错误。
- 根据方法期望的参数个数检查参数数量。
- 用拒绝前导零的正则校验 QUANTITY 字段。
- 用正则校验地址,并可选地校验 EIP-55 校验和。
- 根据允许集合或十六进制区块号校验区块标签。
// validateParams.js — drop-in pre-flight validator
const QUANTITY_RE = /^0x([1-9a-f][0-9a-f]*|0)$/;
const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
const BLOCK_TAGS = new Set(['latest', 'safe', 'finalized', 'earliest', 'pending']);
const SCHEMAS = {
eth_getBalance: { arity: 2, types: ['address', 'blockTag'] },
eth_getTransactionCount: { arity: 2, types: ['address', 'blockTag'] },
eth_call: { arity: 2, types: ['object', 'blockTag'] },
eth_getLogs: { arity: 1, types: ['object'] },
eth_blockNumber: { arity: 0, types: [] },
};
function validateParams(method, params) {
const errors = [];
const schema = SCHEMAS[method];
if (!schema) return [`Unknown method: ${method}`];
if (!Array.isArray(params)) {
errors.push('params must be an array for this method');
return errors;
}
if (params.length !== schema.arity) {
errors.push(`Expected ${schema.arity} params, got ${params.length}`);
}
schema.types.forEach((type, i) => {
const v = params[i];
if (type === 'address' && !ADDRESS_RE.test(v)) errors.push(`param[${i}] invalid address`);
if (type === 'blockTag') {
const ok = BLOCK_TAGS.has(v) || QUANTITY_RE.test(v) || /^0x[0-9a-fA-F]{64}$/.test(v);
if (!ok) errors.push(`param[${i}] invalid block tag`);
}
if (type === 'object' && (typeof v !== 'object' || v === null)) errors.push(`param[${i}] must be an object`);
});
return errors;
}
// Usage
const errs = validateParams('eth_getBalance', ['0x742d35Cc6634C0532925a3b844Bc454e4438f44e', 'latest']);
if (errs.length) console.error('Pre-flight failed:', errs);
else console.log('Request is safe to send');区分 -32602 与相邻错误码
快速分诊取决于知道哪一层失败了。-32600 Invalid Request 表示信封本身格式错误:jsonrpc 版本错误、缺少 method,或 id 类型无效。-32602 表示信封没问题,但参数错误。-32603 Internal error 表示服务器在处理有效请求时遇到故障。
-32000 范围的错误码保留给实现定义的服务器错误。在以太坊客户端中,这些通常代表链特定状况,例如区块超出范围、过滤器未找到,或交易被交易池拒绝。例如,eth_getLogs 调用的区块范围超过节点限制时,可能返回 -32000 范围错误而不是 -32602,因为参数在结构上有效,但请求的范围无法服务。关于这一具体情况,请参阅 eth_getLogs 区块范围限制与大范围扫描。
如果不确定失败是 -32602 还是 -32603,请用 curl 重放完全相同的调用并检查错误对象。code 字段是权威依据;message 字段没有标准化,可能为空或具有误导性。
- -32600:信封格式错误(jsonrpc 版本错误、id 类型错误)。
- -32602:请求格式正确,但参数不可接受。
- -32603:处理有效请求时发生服务端故障。
- -32000 范围:节点/链特定状况,例如区块超出范围。
用 curl 和增量重放定位 -32602
当调用因 -32602 失败时,找到问题参数的最快路径是用 curl 重放完全相同的请求,然后剥离可选参数并逐个重新添加。先发送完整请求确认错误,然后移除最后一个参数并重试。如果错误消失,被移除的参数就是罪魁祸首。
对于带可选参数的方法,例如带 fromBlock 和 toBlock 的 eth_getLogs,请测试每种组合。部分客户端在需要值的地方拒绝 null,另一些则接受 null 作为默认值。记录你的端点表现出哪种行为。
下面的 curl 示例发送一个最小的 eth_getBalance 请求。将 URL 替换为你的 RPC 端点,并调整 params 以复现你的失败。
- 用 curl 重放完全相同的失败调用,确认错误码。
- 剥离可选参数,然后逐个重新添加。
- 对可选字段测试 null 与省略的区别。
- 记录触发 -32602 的确切 params 形式。
curl -X POST https://your-endpoint.example \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"],
"id": 1
}'用结果表记录你的端点容忍度
由于校验规则因客户端和版本而异,了解端点接受什么唯一可靠的方法就是实际测量。构建一个包含方法、params 形式和预期结果的小矩阵,然后针对你依赖的每个端点运行它。用你自己的结果填写下表。
将每一行作为单独请求运行,并记录 HTTP 状态、JSON-RPC 错误码和消息。这为你提供了一个回归基线,可以在客户端升级后重新运行。该表有意留空;这些值需要你来测量,而不是由我们断言。
- Method:JSON-RPC 方法名。
- Client:端点背后的节点软件及版本。
- Params form:位置数组或按名对象。
- Accepted?:是或否。
- Code:返回的 JSON-RPC 错误码(如有)。
- Message:错误消息文本(如有)。
| Method | Client | Params form | Accepted? | Code | Message |
|--------|--------|-------------|-----------|------|---------|
| eth_getBalance | Geth v1.x | positional | | | |
| eth_getBalance | Geth v1.x | by-name | | | |
| eth_getBalance | Erigon v2.x | positional | | | |
| eth_getBalance | Erigon v2.x | by-name | | | |
| eth_call | Geth v1.x | positional | | | |
| eth_getLogs | Geth v1.x | positional | | | |-32602 故障排查清单
按顺序逐项检查以下清单。大多数 -32602 错误都由这些问题之一引起,清单按实际发生频率排序。
如果这些都无法解决错误,问题可能是客户端特定的容忍度。将你的请求与 以太坊 JSON-RPC 规范 和 JSON-RPC 2.0 规范 对照,确认期望的 params 形式。
- 参数顺序错误:位置数组对顺序敏感。
- Quantity 与 data 编码混淆:0x3e8 是 quantity;0x03e8 无效。
- 在需要值的地方使用 null:部分客户端会拒绝必填字段的 null。
- 地址缺少 0x 前缀:务必包含前缀。
- 节点不支持的区块标签:safe 和 finalized 可能并非所有链都可用。
- 向仅支持位置参数的客户端发送按名对象。
- 十六进制 quantity 中存在前导零。
- 完全缺少必填参数。
客户端校验的局限与权衡
JSON-RPC 2.0 规范并不要求提供有信息量的错误消息。服务器可能返回 -32602 而不指明哪个参数失败,这意味着客户端校验是获得精确诊断的唯一途径。这是协议本身的局限,而非任何特定提供商的问题。
校验规则也因客户端版本而异。一个请求在某个端点上通过,可能在另一次升级后于另一个端点上失败;今天可用的按名对象,可能在节点升级后被拒绝。为你调用的每个方法维护 schema 映射是持续的工作,但比调试生产故障更划算。
最后,客户端校验无法捕获只有服务器才能评估的语义错误,例如区块号是有效十六进制但超出链头。这些情况返回 -32000 范围错误,而不是 -32602,需要不同的处理方式。对于依赖状态的调用,请参阅 eth_call 状态覆盖与模拟。
- 规范并不要求服务器指明出错的参数。
- 校验规则因客户端版本而异,且可能在任何升级后变化。
- 客户端校验无法捕获服务端语义错误。
- 维护 schema 映射是持续工作,但能减少生产故障。
稳健处理 RPC 参数的后续步骤
首先将预检校验器添加到你的客户端,并针对最常用的方法运行它。然后为你依赖的每个端点构建结果表,并在客户端升级后重新运行。这为你提供了回归基线,并清晰呈现端点的容忍度。
相关主题请参阅 使用 eth_getTransactionCount 管理 Nonce 了解交易计数参数处理,以及 eth_getLogs 事件与主题过滤 了解过滤器参数校验。如果你正在选择端点,RPC 端点指南 涵盖了端点选择标准。
要探索支持的网络和端点,请访问 以太坊网络页面、OnFinality Learn 中心,或查看 RPC 定价 和 API 服务 了解集成选项。
- 将预检校验器添加到你的客户端。
- 构建结果表并在升级后重新运行。
- 查看其他方法的相关参数处理指南。
- 选择符合你 params 形式要求的端点。