linera-io/linera-protocol · critical
Returned AccountInfo should have code: Some(...) and so code
Error message
Returned AccountInfo should have code: Some(...) and so code_by_hash should never be called
What it means
The mutable (&mut self) twin of the ref variant: this Revm Database impl guarantees every AccountInfo carries its bytecode inline (code: Some), so code_by_hash is never supposed to be called and panics to say so. Reaching it indicates the engine took the by-hash code path, which the inline-code design explicitly rules out.
Source
Thrown at linera-execution/src/evm/database.rs:846
}
fn block_hash_ref(&self, number: u64) -> Result<B256, ExecutionError> {
Ok(keccak256(number.to_string().as_bytes()))
}
}
impl<Runtime> Database for ContractDatabase<Runtime>
where
Runtime: ContractRuntime,
{
type Error = ExecutionError;
fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
self.basic_ref(address)
}
fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
panic!("Returned AccountInfo should have code: Some(...) and so code_by_hash should never be called");
}
fn storage(&mut self, address: Address, index: U256) -> Result<U256, ExecutionError> {
self.storage_ref(address, index)
}
fn block_hash(&mut self, number: u64) -> Result<B256, ExecutionError> {
<Self as DatabaseRef>::block_hash_ref(self, number)
}
}
impl<Runtime> DatabaseCommit for ContractDatabase<Runtime>
where
Runtime: ContractRuntime,
{
fn commit(&mut self, changes: EvmState) {
self.inner.changes = changes;
}View on GitHub (pinned to 6c226ddcb3)
Solutions
- Revert/pin the revm and alloy versions to the ones validated for this codebase.
- Audit any change to basic/basic_ref so they keep returning code: Some(bytecode).
- If the upgrade is required, implement code_by_hash by reading bytecode from contract storage rather than leaving the panic.
Example fix
# Cargo.toml — before (bump triggered the path) revm = "newer" # after — pin to the version the database design assumes revm = "=<previously-validated-version>"
Defensive patterns
Strategy: validation
Validate before calling
# Cargo.lock discipline: pin revm & alloy to the versions the Database design assumes cargo update -p revm --precise <validated-version>
Type guard
// Test invariant: accounts loaded for revm always include their bytecode
let info = db.basic(addr)?.expect("account");
assert!(info.code.is_some(), "code must be inline; code_by_hash must stay unreachable"); Prevention
- Treat any revm/alloy version bump as a breaking change for the EVM DB glue; run full EVM test suites.
- Never strip bytecode from AccountInfo in caching/refactor layers.
- Add a regression test that executes a contract after a state override if such features are enabled.
When it happens
Trigger: A revm version whose Database/DatabaseCommit flow calls code_by_hash during execution or state loading; account-loading code that returns code: None; a custom journaled/override path that stores code by hash. Trigger is engine-internal — normal Linera EVM transactions never reach it.
Common situations: Bumping revm/alloy patch versions that change when the interpreter resolves code; local modifications to the EVM database glue; introducing caching layers that strip bytecode from AccountInfo.
Related errors
- Returned AccountInfo should have code: Some(...) and so code
- owner should be different from spender
- invalid block export configuration: {message}
- An Evm runtime is required to load user applications. Please
- transaction {tx_hash} reverted (receipt status 0)
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/c7727958a0be354d.
Report an issue: GitHub.