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

  1. Build the payload with the Solidity ABI: construct the alloy ...Call struct and call abi_encode so the bytes start with the function selector
  2. Assert payload.len() >= 4 in the client before submitting the operation or query
  3. 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

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


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/c66da171ea0d3cae. Report an issue: GitHub.