{"record":{"id":"4c9c85c0d7eeabdf","repo":"FuelLabs/sway","slug":"abi-encode-size-hint-for","errorCode":null,"errorMessage":"abi_encode_size_hint for [{}]","messagePattern":"abi_encode_size_hint for \\[(.+?)\\]","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sway-core/src/type_system/info.rs","lineNumber":1660,"sourceCode":"                            Some(old_size_hint) => Some(old_size_hint.min(current_size_hint)),\n                            None => Some(current_size_hint),\n                        }\n                    })\n                    .unwrap_or(AbiEncodeSizeHint::Exact(0));\n\n                let max =\n                    decl.variants\n                        .iter()\n                        .fold(AbiEncodeSizeHint::Exact(0), |old_size_hint, v| {\n                            let variant_type = engines.te().get(v.type_argument.type_id);\n                            let current_size_hint = variant_type.abi_encode_size_hint(engines);\n                            old_size_hint.max(current_size_hint)\n                        });\n\n                AbiEncodeSizeHint::range_from_min_max(min, max) + 8\n            }\n\n            x => unimplemented!(\"abi_encode_size_hint for [{}]\", engines.help_out(x)),\n        }\n    }\n\n    /// Returns a [String] representing the type.\n    /// When the type is monomorphized and does not contain [TypeInfo::Custom] types,\n    /// the returned string is unique.\n    /// Two monomorphized types that do not contain [TypeInfo::Custom] types,\n    /// that generate the same string can be assumed to be the same.\n    pub fn get_type_str(&self, engines: &Engines) -> String {\n        use TypeInfo::*;\n        match self {\n            Unknown => \"unknown\".into(),\n            Never => \"never\".into(),\n            UnknownGeneric { name, .. } => name.to_string(),\n            Placeholder(_) => \"_\".into(),\n            TypeParam(param) => format!(\"typeparam({})\", param.name()),\n            StringSlice => \"str\".into(),\n            StringArray(length) => {","sourceCodeStart":1642,"sourceCodeEnd":1678,"githubUrl":"https://github.com/FuelLabs/sway/blob/47e5e902faa42baf652dd6a0c88cd23390c1a614/sway-core/src/type_system/info.rs#L1642-L1678","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the type printed in the message between the brackets - it names the exact unsupported TypeInfo - and remove or replace that field.","Convert contract addresses to Bits256/Address/B256 (plain 32-byte types with arms) before embedding them in an encoded struct.","Annotate generics with concrete types so nothing reaches encoding as unresolved Custom.","Upgrade sway; size-hint coverage and custom AbiEncode impl detection have improved since the referenced TODO."],"exampleFix":"// before\nstruct Msg { to: ContractId, amount: u64 } // ContractId-containing encode fails\n// msg.abi_encode()\n\n// after\nstruct Msg { to: b256, amount: u64 } // b256 has Exact(32) hint\n// Msg { to: to.into(), amount }.abi_encode()","handlingStrategy":"type-guard","validationCode":"// Sway-side: before encoding, ensure the value's type contains only supported kinds.\n// Supported: bool, u8..u64, u256, b256, numeric, arrays/str-arrays/tuples/structs/enums/aliases\n// of supported types. Unsupported: contract, contract caller, unresolved custom/generic.","typeGuard":"// Rust-side helper for tooling that inspects Sway types before abi_encode:\nfn is_abi_size_hint_safe(ti: &TypeInfo, engines: &Engines) -> bool {\n    use TypeInfo::*;\n    match ti {\n        Boolean | UnsignedInteger(_) | Numeric | B256 => true,\n        Unknown | UnknownGeneric{..} | ErrorRecovery(_) | Ref{..} | Slice(_)\n        | RawUntypedSlice | StringSlice | RawUntypedPtr | Ptr(_) => true, // PotentiallyInfinite arms\n        Alias{..} | Array{..} | StringArray(_) | Tuple(_) | Struct(_) | Enum(_) => true,\n        // everything else (Contract, ContractCaller, Custom, ...) -> false\n        _ => false,\n    }\n}","tryCatchPattern":"// unimplemented! panics; catch_unwind at the boundary if you invoke the compiler:\nlet r = std::panic::catch_unwind(|| value.abi_encode());\nif r.is_err() { /* report unsupported type inside the encoded value */ }","preventionTips":["Never embed contract/contract-caller types in structs you abi_encode; convert to b256 first.","Keep encoded message types to primitives, arrays, tuples, structs, enums.","Resolve all generics to concrete types before encoding.","On compiler errors, read the TypeInfo printed in brackets to find the offending field."],"tags":["sway","abi-encode","type-system","compiler","panic"],"backgroundTag":null,"analyzedSha":"47e5e902faa42baf652dd6a0c88cd23390c1a614","analyzedAt":"2026-08-16T07:57:45.555Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}