FuelLabs/sway · error

abi_encode_size_hint for [{}]

Error message

abi_encode_size_hint for [{}]

What it means

TypeInfo::abi_encode_size_hint computes how large the abi-encode buffer for a type must be. Primitives, numeric widths, b256, arrays, string arrays, tuples, structs, enums, aliases and potentially-infinite types (slices, raw ptrs, refs, unknowns, error recovery) all have arms; every remaining TypeInfo variant falls into the catch-all unimplemented! that prints the offending type with engines.help_out. In this sway version the unhandled variants are the contract/contract-caller and unresolved Custom types (see the TODO at sway issue #5727 in the source about custom AbiEncode impls).

Source

Thrown at sway-core/src/type_system/info.rs:1660

                            Some(old_size_hint) => Some(old_size_hint.min(current_size_hint)),
                            None => Some(current_size_hint),
                        }
                    })
                    .unwrap_or(AbiEncodeSizeHint::Exact(0));

                let max =
                    decl.variants
                        .iter()
                        .fold(AbiEncodeSizeHint::Exact(0), |old_size_hint, v| {
                            let variant_type = engines.te().get(v.type_argument.type_id);
                            let current_size_hint = variant_type.abi_encode_size_hint(engines);
                            old_size_hint.max(current_size_hint)
                        });

                AbiEncodeSizeHint::range_from_min_max(min, max) + 8
            }

            x => unimplemented!("abi_encode_size_hint for [{}]", engines.help_out(x)),
        }
    }

    /// Returns a [String] representing the type.
    /// When the type is monomorphized and does not contain [TypeInfo::Custom] types,
    /// the returned string is unique.
    /// Two monomorphized types that do not contain [TypeInfo::Custom] types,
    /// that generate the same string can be assumed to be the same.
    pub fn get_type_str(&self, engines: &Engines) -> String {
        use TypeInfo::*;
        match self {
            Unknown => "unknown".into(),
            Never => "never".into(),
            UnknownGeneric { name, .. } => name.to_string(),
            Placeholder(_) => "_".into(),
            TypeParam(param) => format!("typeparam({})", param.name()),
            StringSlice => "str".into(),
            StringArray(length) => {

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Read the type printed in the message between the brackets - it names the exact unsupported TypeInfo - and remove or replace that field.
  2. Convert contract addresses to Bits256/Address/B256 (plain 32-byte types with arms) before embedding them in an encoded struct.
  3. Annotate generics with concrete types so nothing reaches encoding as unresolved Custom.
  4. Upgrade sway; size-hint coverage and custom AbiEncode impl detection have improved since the referenced TODO.

Example fix

// before
struct Msg { to: ContractId, amount: u64 } // ContractId-containing encode fails
// msg.abi_encode()

// after
struct Msg { to: b256, amount: u64 } // b256 has Exact(32) hint
// Msg { to: to.into(), amount }.abi_encode()
Defensive patterns

Strategy: type-guard

Validate before calling

// Sway-side: before encoding, ensure the value's type contains only supported kinds.
// Supported: bool, u8..u64, u256, b256, numeric, arrays/str-arrays/tuples/structs/enums/aliases
// of supported types. Unsupported: contract, contract caller, unresolved custom/generic.

Type guard

// Rust-side helper for tooling that inspects Sway types before abi_encode:
fn is_abi_size_hint_safe(ti: &TypeInfo, engines: &Engines) -> bool {
    use TypeInfo::*;
    match ti {
        Boolean | UnsignedInteger(_) | Numeric | B256 => true,
        Unknown | UnknownGeneric{..} | ErrorRecovery(_) | Ref{..} | Slice(_)
        | RawUntypedSlice | StringSlice | RawUntypedPtr | Ptr(_) => true, // PotentiallyInfinite arms
        Alias{..} | Array{..} | StringArray(_) | Tuple(_) | Struct(_) | Enum(_) => true,
        // everything else (Contract, ContractCaller, Custom, ...) -> false
        _ => false,
    }
}

Try / catch

// unimplemented! panics; catch_unwind at the boundary if you invoke the compiler:
let r = std::panic::catch_unwind(|| value.abi_encode());
if r.is_err() { /* report unsupported type inside the encoded value */ }

Prevention

When it happens

Trigger: Calling .abi_encode() (or any API that needs the size hint, such as padded encodes) on a value whose type is, or transitively contains, a TypeInfo variant without a size-hint arm - e.g. a ContractCaller or contract type stored in a struct/enum/tuple being encoded.

Common situations: Encoding a config/message struct that accidentally includes a contract caller or contract id wrapper; generics left unresolved (Custom) reaching encoding; code that worked with plain Address/B256 breaking after swapping in ContractId/contract types.

Related errors


AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16). Data as JSON: /api/errors/4c9c85c0d7eeabdf. Report an issue: GitHub.