linera-io/linera-protocol · error · EvmExecutionError
The operation should contain the evm selector and so have le
Error message
The operation should contain the evm selector and so have length 4 or more
What it means
Every call into an EVM application is addressed by a 4-byte ABI selector, so the runtime refuses operation or query payloads shorter than 4 bytes. ensure_message_length is called from execute_operation, handle_query and init_transact before any selector is parsed; a shorter payload is rejected with OperationIsTooShort because it cannot be a valid ABI-encoded call.
Source
Thrown at linera-execution/src/evm/inputs.rs:192
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> {
ensure!(
actual_length >= min_length,
EvmExecutionError::OperationIsTooShort
);
Ok(())
}
pub(crate) fn ensure_selector_presence(
module: &[u8],
selector: &[u8],
fct_name: &str,
) -> Result<(), EvmExecutionError> {
ensure!(
has_selector(module, selector),
EvmExecutionError::MissingFunction(fct_name.to_string())
);
Ok(())
}
View on GitHub (pinned to 6c226ddcb3)
Solutions
- Build the payload with the Solidity ABI: construct the alloy ...Call struct and call abi_encode so the bytes start with the function selector
- Assert payload.len() >= 4 in the client before submitting the operation or query
- If you intended a bcs or empty payload, verify the target application is a Wasm application, not an EVM one
Example fix
// before: raw encoded args, no 4-byte selector
let query = serde_json::to_vec(&MyQuery::Get)?;
let result = client.query_application(app_id, query).await?;
// after: ABI-encoded call with selector
let query = getCall { key: key }.abi_encode();
let result = client.query_application(app_id, query).await?; Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_evm_payload(payload: &[u8]) -> bool {
payload.len() >= 4 // a 4-byte ABI selector is the minimum
}
assert!(is_valid_evm_payload(&op), "EVM payload must start with a 4-byte selector"); Type guard
fn is_operation_too_short(err: &ExecutionError) -> bool {
matches!(
err,
ExecutionError::EvmError(EvmExecutionError::OperationIsTooShort)
)
} Try / catch
match client.query_application(app_id, query).await {
Ok(bytes) => bytes,
Err(ref e) if is_operation_too_short(e) => {
return Err(anyhow!("payload was not ABI-encoded; rebuild it with abi_encode()"))
}
Err(e) => return Err(e.into()),
} Prevention
- Always build EVM payloads with alloy's SolCall::abi_encode, which guarantees the selector prefix
- Add a client-side length assertion before every submit or query of an EVM application
- Keep Wasm (bcs) and EVM (ABI) payload builders in separate, clearly named modules to avoid mix-ups
When it happens
Trigger: Calling an EVM application's operation or query endpoint with an empty Vec<u8> or fewer than 4 bytes: passing raw bcs/json-encoded arguments without the 4-byte selector prefix, or submitting an empty payload.
Common situations: Client code that bcs-encodes a struct and submits it to an EVM app (correct for Wasm apps, invalid for EVM); reusing Wasm-style test payloads against an EVM application; refactoring an operation builder and accidentally dropping the selector bytes.
Related errors
- expected exactly 2 topics (signature + indexed depositor), g
- expected 224 bytes of event data (7 x 32), got {}
- invalid ABI encoding: depositor topic padding bytes (0..12)
- invalid ABI encoding: address padding bytes (128..140) must
- The balances are incoherent for address {0}, balances {1}, {
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/c66da171ea0d3cae.
Report an issue: GitHub.