linera-io/linera-protocol · error · ExecutionError

BlockTooLarge

BlockTooLarge

Error message

ExecutionError::BlockTooLarge

What it means

track_block_size accumulates the serialized size of block contents (fed by track_block_size_of during block construction); exceeding maximum_block_size, or overflowing the u64 accumulator, fails with BlockTooLarge (resources.rs:840). Oversized blocks are rejected before they can be proposed, keeping block propagation and storage bounded.

Source

Thrown at linera-execution/src/resources.rs:840

}

impl<Account, Tracker> ResourceController<Account, Tracker>
where
    Tracker: AsMut<ResourceTracker>,
{
    /// Tracks the serialized size of a block, or parts of it.
    pub fn track_block_size_of(&mut self, data: &impl Serialize) -> Result<(), ExecutionError> {
        self.track_block_size(bcs::serialized_size(data)?)
    }

    /// Tracks the serialized size of a block, or parts of it.
    pub fn track_block_size(&mut self, size: usize) -> Result<(), ExecutionError> {
        let tracker = self.tracker.as_mut();
        tracker.block_size = u64::try_from(size)
            .ok()
            .and_then(|size| tracker.block_size.checked_add(size))
            .ok_or(ExecutionError::BlockTooLarge)?;
        ensure!(
            tracker.block_size <= self.policy.maximum_block_size,
            ExecutionError::BlockTooLarge
        );
        Ok(())
    }
}

impl ResourceController<Option<AccountOwner>, ResourceTracker> {
    /// Provides a reference to the current execution state and obtains a temporary object
    /// where the accounting functions of [`ResourceController`] are available.
    pub async fn with_state<'a, C>(
        &mut self,
        view: &'a mut SystemExecutionStateView<C>,
    ) -> Result<ResourceController<Sources<'a>, &mut ResourceTracker>, ViewError>
    where
        C: Context + Clone + 'static,
    {
        self.with_state_and_grant(view, None).await

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Split the block: propose smaller batches of operations
  2. Move large payloads into blobs and reference them by BlobId instead of inlining the bytes
  3. If you operate the network, raise maximum_block_size in the resource policy

Example fix

// before: inline large payload in an operation
let op = Operation::Upload(data.to_vec());

// after: publish blob first, reference by id
let blob_id = publish_blob(data).await?;
let op = Operation::Reference(blob_id);
Defensive patterns

Strategy: validation

Validate before calling

// Track serialized sizes while building the block; stop before exceeding the cap
fn fits_block_size(ops: &[Operation], policy: &ResourceControlPolicy) -> Result<bool, Error> {
    let size: usize = ops.iter().map(bcs::serialized_size).sum::<Result<usize, _>>()?;
    Ok(size as u64 <= policy.maximum_block_size)
}

if !fits_block_size(&pending_ops, policy)? {
    pending_ops.truncate(pending_ops.len() - 1); // shed operations until it fits
}

Type guard

fn is_block_too_large(err: &ExecutionError) -> bool {
    matches!(err, ExecutionError::BlockTooLarge)
}

Try / catch

match proposer.propose(block).await {
    Ok(h) => h,
    Err(ref e) if is_block_too_large(e) => {
        // fallback: split the block and propose the halves sequentially
        let (a, b) = block.operations.split_at(block.operations.len() / 2);
        propose_all(vec![a.to_vec(), b.to_vec()]).await
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Building a block whose BCS-serialized operations and messages exceed the policy's maximum_block_size; also any size accounting addition that overflows the u64 total.

Common situations: Blocks bundling many operations or inlining large payloads; high-throughput producers that do not batch-limit; policies tightened in a new epoch; blob content referenced inline instead of by blob id.

Related errors


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