From cd6e895a97b37151177dfc8a22bd1e0878028eaa Mon Sep 17 00:00:00 2001 From: Emma Jamieson-Hoare Date: Thu, 19 Feb 2026 12:32:31 +0000 Subject: [PATCH] fix(rpc): return -32602 for PayloadAttributes structure validation errors (#22374) Co-authored-by: yongkangc --- crates/rpc/rpc-engine-api/src/error.rs | 40 +++++++++++++++----------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/crates/rpc/rpc-engine-api/src/error.rs b/crates/rpc/rpc-engine-api/src/error.rs index 6155c004c3..ec0f0544dd 100644 --- a/crates/rpc/rpc-engine-api/src/error.rs +++ b/crates/rpc/rpc-engine-api/src/error.rs @@ -14,8 +14,6 @@ use thiserror::Error; /// The Engine API result type pub type EngineApiResult = Result; -/// Invalid payload attributes code. -pub const INVALID_PAYLOAD_ATTRIBUTES: i32 = -38003; /// Payload unsupported fork code. pub const UNSUPPORTED_FORK_CODE: i32 = -38005; /// Payload unknown error code. @@ -26,9 +24,6 @@ pub const REQUEST_TOO_LARGE_CODE: i32 = -38004; /// Error message for the request too large error. const REQUEST_TOO_LARGE_MESSAGE: &str = "Too large request"; -/// Error message for the request too large error. -const INVALID_PAYLOAD_ATTRIBUTES_MSG: &str = "Invalid payload attributes"; - /// Error returned by [`EngineApi`][crate::EngineApi] /// /// Note: This is a high-fidelity error type which can be converted to an RPC error that adheres to @@ -120,7 +115,13 @@ impl From for jsonrpsee_types::error::ErrorObject<'static> { EngineApiError::InvalidBodiesRange { .. } | EngineApiError::EngineObjectValidationError( EngineObjectValidationError::Payload(_) | - EngineObjectValidationError::InvalidParams(_), + EngineObjectValidationError::InvalidParams(_) | + // Per Engine API spec, structure validation errors for PayloadAttributes + // (e.g., missing withdrawals post-Shanghai, missing parentBeaconBlockRoot + // post-Cancun) should return -32602 "Invalid params", not -38003. + // See: https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md + // Fixes: https://github.com/paradigmxyz/reth/issues/8732 + EngineObjectValidationError::PayloadAttributes(_), ) | EngineApiError::UnexpectedRequestsHash => { // Note: the data field is not required by the spec, but is also included by other @@ -131,17 +132,6 @@ impl From for jsonrpsee_types::error::ErrorObject<'static> { Some(ErrorData::new(error)), ) } - EngineApiError::EngineObjectValidationError( - EngineObjectValidationError::PayloadAttributes(_), - ) => { - // Note: the data field is not required by the spec, but is also included by other - // clients - jsonrpsee_types::error::ErrorObject::owned( - INVALID_PAYLOAD_ATTRIBUTES, - INVALID_PAYLOAD_ATTRIBUTES_MSG, - Some(ErrorData::new(error)), - ) - } EngineApiError::UnknownPayload => jsonrpsee_types::error::ErrorObject::owned( UNKNOWN_PAYLOAD_CODE, error.to_string(), @@ -208,6 +198,7 @@ impl From for jsonrpsee_types::error::ErrorObject<'static> { mod tests { use super::*; use alloy_rpc_types_engine::ForkchoiceUpdateError; + use reth_payload_primitives::VersionSpecificValidationError; #[track_caller] fn ensure_engine_rpc_error( @@ -246,6 +237,8 @@ mod tests { )), ); + // ForkchoiceUpdateError::UpdatedInvalidPayloadAttributes is for semantic validation + // errors that occur AFTER the structure check passes, so it returns -38003 ensure_engine_rpc_error( -38003, "Invalid payload attributes", @@ -259,5 +252,18 @@ mod tests { "Unknown payload", EngineApiError::UnknownPayload, ); + + // PayloadAttributes structure validation errors (e.g., missing withdrawals post-Shanghai) + // should return -32602 per the Engine API spec + // See: https://github.com/paradigmxyz/reth/issues/8732 + ensure_engine_rpc_error( + INVALID_PARAMS_CODE, + INVALID_PARAMS_MSG, + EngineApiError::EngineObjectValidationError( + EngineObjectValidationError::PayloadAttributes( + VersionSpecificValidationError::NoWithdrawalsPostShanghai, + ), + ), + ); } }