slint-ui/slint · error · proc_macro::Error

The type of an #[field_offset] member in the vtable must be…

Error message

The type of an #[field_offset] member in the vtable must be 'usize'

What it means

Members of a #[vtable] struct annotated with #[field_offset(...)] represent byte offsets of fields in the concrete struct, so the macro requires them to be of type usize. Any other type on a #[field_offset] member is rejected at compile time.

Solutions

  1. Change the #[field_offset] member's type to usize.
  2. Remove the #[field_offset] attribute if the member is not meant to be an offset.

Example fix

// before
#[vtable]
struct FooVTable {
    #[field_offset(data)]
    data_offset: u32,
}
// after
#[vtable]
struct FooVTable {
    #[field_offset(data)]
    data_offset: usize,
}
Defensive patterns

Strategy: validation

Validate before calling

let _: usize = data_offset; // every #[field_offset] member is usize

Prevention

When it happens

Trigger: Declaring e.g. `#[field_offset(foo)] x: u32` or `*const u8` inside a #[vtable] struct instead of `usize`.

Common situations: Guessing the offset-member type when hand-writing a vtable; copying an ordinary struct field declaration for the offset member.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/9e8389801bc60756. Report an issue: GitHub.

Appendix: source

Thrown at helper_crates/vtable/macro/macro.rs:588

                    items: Vec::new(),
                    ..generated_trait.clone()
                });

            let const_type = if let Some(o) = field
                .attrs
                .iter()
                .position(|a| a.path().get_ident().map(|a| a == "field_offset").unwrap_or(false))
            {
                let a = field.attrs.remove(o);
                let member_type = match a.parse_args::<Type>() {
                    Err(e) => return e.to_compile_error().into(),
                    Ok(ty) => ty,
                };

                match &field.ty {
                    Type::Path(p) if p.path.get_ident().map(|i| i == "usize").unwrap_or(false) => {}
                    ty => {
                        return Error::new(
                            ty.span(),
                            "The type of an #[field_offset] member in the vtable must be 'usize'",
                        )
                        .to_compile_error()
                        .into();
                    }
                }

                // add `: Sized` to the trait in case it does not have it
                if generated_trait_assoc_const.supertraits.is_empty() {
                    generated_trait_assoc_const.colon_token = Some(Default::default());
                    generated_trait_assoc_const.supertraits.push(parse_quote!(Sized));
                }

                let offset_type: Type = parse_quote!(vtable::FieldOffset<Self, #member_type>);

                vtable_ctor.push(quote!(#ident: T::#ident.get_byte_offset(),));

View on GitHub (pinned to bb937076de)