FuelLabs/fuels-rs · error · syn::Error
must have exactly one element
Error message
must have exactly one element
What it means
Compile-time error from the fuels macros crate: when deriving Fuel-typed ABI encoding for an enum, a variant with unnamed (tuple) fields must carry exactly one field. The derive walks each variant and treats a single unnamed field as the variant's payload type; anything else (0 fields is fine as Unit, but 2+ unnamed fields, or the error span on the parens) is rejected with this message.
Source
Thrown at packages/fuels-macros/src/parse_utils.rs:163
Ok(Members {
members,
fuels_core_path,
})
}
pub(crate) fn from_enum(data: DataEnum, fuels_core_path: TokenStream) -> syn::Result<Self> {
let members = data
.variants
.into_iter()
.map(|variant: Variant| {
let name = variant.ident;
if has_ignore_attr(&variant.attrs) {
Ok(Member::Ignored { name })
} else {
let ty = match variant.fields {
Fields::Unnamed(fields_unnamed) => {
if fields_unnamed.unnamed.len() != 1 {
return Err(Error::new(
fields_unnamed.paren_token.span.join(),
"must have exactly one element",
));
}
fields_unnamed.unnamed.into_iter().next()
}
Fields::Unit => None,
Fields::Named(named_fields) => {
return Err(Error::new_spanned(
named_fields,
"struct-like enum variants are not supported",
));
}
}
.map(|field| field.ty.into_token_stream())
.unwrap_or_else(|| quote! {()});
Ok(Member::Normal { name, ty })
}View on GitHub (pinned to d9a250a518)
Solutions
- Reduce each tuple variant to exactly one field, wrapping extras in a struct: TooMany(Pair) where struct Pair { a: u64, b: bool } and derive on the struct too.
- If the extra field is a marker (PhantomData), move it into a wrapper struct instead of the variant.
- Alternatively switch the variant to unit-only and pass data through a separate type.
- Check for an #[ignore] attribute if the variant is intentionally not part of the ABI (has_ignore_attr skips it).
Example fix
// before
#[derive(FuelTypes)]
enum Status {
Failed(String, u64),
}
// after
#[derive(FuelTypes)]
struct Failure {
msg: String,
code: u64,
}
#[derive(FuelTypes)]
enum Status {
Failed(Failure),
} Defensive patterns
Strategy: validation
Type guard
// compile-time 'guard': keep tuple variants single-field by construction
trait FuelAbiEnumShape {
const OK: bool;
}
// convention: any enum used in ABI types has variants of form V(T) or V; reject V(T, U) in review
fn _assert_single_payload<T, U>() where U: FuelAbiEnumShape {} Prevention
- Model multi-field payloads as a struct and derive the Fuel types on the struct too.
- Run cargo check on the crate as soon as the derive is added — this error is compile-time.
- Check for an #[ignore] attribute if the variant must stay in the enum but out of the ABI.
When it happens
Trigger: Applying #[derive(FuelTypes)]/the fuels type-generation derive (directly or via the macro pipeline in packages/fuels-macros) to an enum with a variant like TooMany(u64, bool) or NoFields() — i.e. Fields::Unnamed whose unnamed.len() != 1. Named-field variants fail separately ('struct-like enum variants are not supported'); unit variants are allowed.
Common situations: Porting a Rust enum with multi-field tuple variants to a Fuel contract type; modeling sum types the way serde/serde_json allow and expecting the same flexibility; adding a second field for metadata (e.g. MyVariant(Data, PhantomData)).
Related errors
- expected name='value'
- missing attribute '{name}'
- Unrecognized command. Expected one of: {msg}
- Only one `Abigen` command allowed
- Add an `Abigen(..)` command!
AI-assisted analysis of FuelLabs/fuels-rs@d9a250a518 (2026-08-16).
Data as JSON: /api/errors/a622febd5218b7e5.
Report an issue: GitHub.