{"record":{"id":"526c5de1ad61652a","repo":"linera-io/linera-protocol","slug":"it-is-illegal-to-call-function-execute-message-fro","errorCode":null,"errorMessage":"It is illegal to call function execute_message from an operation","messagePattern":"It is illegal to call function execute_message from an operation","errorType":"validation","errorClass":"EvmExecutionError","httpStatus":null,"severity":"error","filePath":"linera-execution/src/evm/inputs.rs","lineNumber":169,"sourceCode":"/// only from a submitted message\npub(crate) const EXECUTE_MESSAGE_SELECTOR: &[u8] = &[173, 125, 234, 205];\n\n/// This is the selector of `process_streams` that should be called\n/// only from a submitted message\npub(crate) const PROCESS_STREAMS_SELECTOR: &[u8] =\n    &<process_streamsCall as alloy_sol_types::SolCall>::SELECTOR;\n\n/// This is the selector of `summarize_events`, which is called by the system on a\n/// checkpoint and never from a submitted operation.\npub(crate) const SUMMARIZE_EVENTS_SELECTOR: &[u8] =\n    &<summarize_eventsCall as alloy_sol_types::SolCall>::SELECTOR;\n\n/// This is the selector of `instantiate` that should be called\n/// only when creating a new instance of a shared contract\npub(crate) const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];\n\npub(crate) fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {\n    ensure!(\n        vec != EXECUTE_MESSAGE_SELECTOR,\n        EvmExecutionError::IllegalOperationCall(\"function execute_message\".to_string(),)\n    );\n    ensure!(\n        vec != PROCESS_STREAMS_SELECTOR,\n        EvmExecutionError::IllegalOperationCall(\"function process_streams\".to_string(),)\n    );\n    ensure!(\n        vec != SUMMARIZE_EVENTS_SELECTOR,\n        EvmExecutionError::IllegalOperationCall(\"function summarize_events\".to_string(),)\n    );\n    ensure!(\n        vec != INSTANTIATE_SELECTOR,\n        EvmExecutionError::IllegalOperationCall(\"function instantiate\".to_string(),)\n    );\n    Ok(())\n}\n","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-execution/src/evm/inputs.rs#L151-L187","documentation":"Raised by linera-execution's forbid_execute_operation_origin, called from the EVM module's execute_operation and init_transact: the 4-byte selector at the start of the operation's calldata must not equal EXECUTE_MESSAGE_SELECTOR ([173, 125, 234, 205]), the reserved entry point that only the system may invoke when delivering a cross-chain message. Submitting an operation whose target function collides with that selector is rejected before execution because user operations must enter the contract through ordinary entry points.","triggerScenarios":"An EVM operation whose calldata starts with bytes 0xad7deacd — either deliberately calling execute_message from an operation, or a Solidity function whose ABI hash happens to collide with the reserved selector; transact requests (init_transact) routing the same selector.","commonSituations":"Porting contracts that expose a function named execute_message(bytes); rare 4-byte ABI collisions with unrelated function signatures; tooling that forwards message payloads as operations instead of sending messages.","solutions":["Rename the Solidity function or change its signature so its selector differs (any change to name/arg types rehashes the selector)","If you meant to deliver a message, use Linera's message sending instead of an operation","Check the operation payload's first four bytes before submission and reject 0xad7deacd client-side"],"exampleFix":"// Solidity: rename to change the selector\n// before\nfunction execute_message(bytes calldata data) external { ... }\n// after\nfunction handle_incoming(bytes calldata data) external { ... }","handlingStrategy":"validation","validationCode":"const EXECUTE_MESSAGE_SELECTOR: [u8; 4] = [173, 125, 234, 205];\n\nfn targets_reserved_entrypoint(calldata: &[u8]) -> bool {\n    calldata.get(..4) == Some(&EXECUTE_MESSAGE_SELECTOR[..])\n}\n\nassert!(!targets_reserved_entrypoint(&operation_calldata), \"operations must not call execute_message\");","typeGuard":"fn is_illegal_execute_message_call(err: &ExecutionError) -> bool {\n    matches!(\n        err,\n        ExecutionError::EvmError(evm_error!::IllegalOperationCall(ref f)) if f.contains(\"execute_message\")\n    )\n}","tryCatchPattern":"match client.execute_operations(ops, vec![]).await {\n    Err(e) if is_illegal_execute_message_call(&e) => {\n        // Reject the offending operation at the source; rename the contract entry point.\n        Err(anyhow::anyhow!(\"operation targets reserved execute_message selector: {e}\"))\n    }\n    other => other,\n}","preventionTips":["Never name a public contract function execute_message with the system signature; rename wrapper functions","Validate calldata selectors client-side before submitting operations (the 4-byte check above)","Deliver messages through Linera's message/stream API, not by invoking message entry points from operations"],"tags":["linera","evm","solidity","selector","entry-point","validation"],"backgroundTag":"reserved-entrypoint-invocation","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}