linera-io/linera-protocol · error · EvmExecutionError
It is illegal to call function process_streams from an opera
Error message
It is illegal to call function process_streams from an operation
What it means
Second guard in forbid_execute_operation_origin (used by execute_operation and init_transact): the operation calldata's 4-byte selector must not equal PROCESS_STREAMS_SELECTOR, the reserved function the system calls on an EVM contract when delivering stream messages. Invoking process_streams from a user operation is rejected before execution because it would let operations fake system-driven stream processing.
Source
Thrown at linera-execution/src/evm/inputs.rs:173
/// only from a submitted message
pub(crate) const PROCESS_STREAMS_SELECTOR: &[u8] =
&<process_streamsCall as alloy_sol_types::SolCall>::SELECTOR;
/// This is the selector of `summarize_events`, which is called by the system on a
/// checkpoint and never from a submitted operation.
pub(crate) const SUMMARIZE_EVENTS_SELECTOR: &[u8] =
&<summarize_eventsCall as alloy_sol_types::SolCall>::SELECTOR;
/// This is the selector of `instantiate` that should be called
/// only when creating a new instance of a shared contract
pub(crate) const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];
pub(crate) fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {
ensure!(
vec != EXECUTE_MESSAGE_SELECTOR,
EvmExecutionError::IllegalOperationCall("function execute_message".to_string(),)
);
ensure!(
vec != PROCESS_STREAMS_SELECTOR,
EvmExecutionError::IllegalOperationCall("function process_streams".to_string(),)
);
ensure!(
vec != SUMMARIZE_EVENTS_SELECTOR,
EvmExecutionError::IllegalOperationCall("function summarize_events".to_string(),)
);
ensure!(
vec != INSTANTIATE_SELECTOR,
EvmExecutionError::IllegalOperationCall("function instantiate".to_string(),)
);
Ok(())
}
pub(crate) fn ensure_message_length(
actual_length: usize,
min_length: usize,
) -> Result<(), EvmExecutionError> {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Rename the function or alter its parameter types so its selector no longer matches process_streams
- Route stream processing through actual message/stream delivery rather than operations
- Pre-check the calldata selector client-side before submitting the operation
Example fix
// Solidity: rename to change the selector
// before
function process_streams(bytes calldata input) external { ... }
// after
function apply_stream_events(bytes calldata input) external { ... } Defensive patterns
Strategy: validation
Validate before calling
fn targets_process_streams(calldata: &[u8], process_streams_selector: [u8; 4]) -> bool {
calldata.get(..4) == Some(&process_streams_selector[..])
}
// compute the selector from your contract ABI, e.g. keccak("process_streams(...)")[..4]
assert!(!targets_process_streams(&operation_calldata, selector)); Type guard
fn is_illegal_process_streams_call(err: &ExecutionError) -> bool {
matches!(
err,
ExecutionError::EvmError(evm_error!::IllegalOperationCall(ref f)) if f.contains("process_streams")
)
} Try / catch
match client.execute_operations(ops, vec![]).await {
Err(e) if is_illegal_process_streams_call(&e) => {
Err(anyhow::anyhow!("operation targets reserved process_streams selector: {e}"))
}
other => other,
} Prevention
- Keep system stream entry points out of your contract's external ABI (mark them internal)
- Check generated bindings: some generators expose system functions as callable wrappers
- Add a CI check that fails if any exported function's selector equals the reserved ones
When it happens
Trigger: An EVM operation or transact request whose calldata begins with the process_streams selector — a Solidity function with the same name/signature (common in stream-subscription contracts ported verbatim), or an ABI collision with an unrelated function hashing to the same 4 bytes.
Common situations: Contracts generated from Linera's EVM interface ABI re-exposing process_streams as public; hand-written wrappers around the stream API invoked via operations; selector collisions from large contracts (probability grows with many functions).
Related errors
- It is illegal to call function execute_message from an opera
- It is illegal to call function summarize_events from an oper
- It is illegal to call function instantiate from an operation
- The balances are incoherent for address {0}, balances {1}, {
- The function {0} is being called but is missing from the byt
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/240a5370f8adf7d9.
Report an issue: GitHub.