FuelLabs/fuel-core · error · Error::Serialization

Missing script result payload

Error message

Missing script result payload

What it means

receipt_from_proto requires the ScriptResult receipt's result sub-message, which carries the ScriptExecutionResult; prost yields None when it is absent, and the code maps that to Error::Serialization. Without it there is no way to build FuelReceipt::script_result, so the block decode fails.

Source

Thrown at crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs:439

        ProtoReceiptVariant::TransferOut(transfer) => {
            let id = ContractId::try_from(transfer.id.as_slice())
                .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let to = Address::try_from(transfer.to.as_slice())
                .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let asset_id = AssetId::try_from(transfer.asset_id.as_slice())
                .map_err(|e| Error::Serialization(anyhow!(e)))?;
            Ok(FuelReceipt::transfer_out(
                id,
                to,
                transfer.amount,
                asset_id,
                transfer.pc,
                transfer.is,
            ))
        }
        ProtoReceiptVariant::ScriptResult(result) => {
            let script_result = result.result.as_ref().ok_or_else(|| {
                Error::Serialization(anyhow!("Missing script result payload"))
            })?;
            let execution_result = script_execution_result_from_proto(script_result)?;
            Ok(FuelReceipt::script_result(
                execution_result,
                result.gas_used,
            ))
        }
        ProtoReceiptVariant::MessageOut(msg) => {
            let sender = Address::try_from(msg.sender.as_slice())
                .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let recipient = Address::try_from(msg.recipient.as_slice())
                .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let nonce = Nonce::try_from(msg.nonce.as_slice())
                .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let digest = Bytes32::try_from(msg.digest.as_slice()).map_err(|e| {
                Error::Serialization(anyhow!(
                    "Could not convert message digest to Bytes32: {}",
                    e

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Debug-print the failing ScriptResult receipt to confirm result is None.
  2. Fix the encoder to always embed the ScriptExecutionResult sub-message.
  3. Pre-validate presence of result on ScriptResult receipts before decoding.
  4. Re-fetch the block from a compatible peer.

Example fix

// before
let script_result = result.result.as_ref().ok_or_else(|| {
    Error::Serialization(anyhow!("Missing script result payload"))
})?;

// after: pre-validate with position context
if let ProtoReceiptVariant::ScriptResult(sr) = variant {
    if sr.result.is_none() {
        return Err(Error::Serialization(anyhow::anyhow!(
            "receipt[{i}] ScriptResult missing result payload"
        )));
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

fn script_result_payload_present(sr: &ProtoScriptResult) -> bool {
    sr.result.is_some()
}

Type guard

fn script_result_complete(sr: &ProtoScriptResult) -> bool {
    sr.result.is_some()
}

Try / catch

match receipt_from_proto(r) {
    Ok(receipt) => out.push(receipt),
    Err(Error::Serialization(ctx)) if ctx.to_string().contains("script result") => {
        tracing::warn!(?r, "rejecting ScriptResult without payload");
        return Err(Error::Serialization(ctx));
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Decoding a proto block where a ScriptResult receipt omits the nested result message - encoder skips it, data truncated, or a fixture that sets only gas_used.

Common situations: Version skew across schema changes; producers that write partial receipts; fuzzing.

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/3a09bf5c9b9bf6f1. Report an issue: GitHub.