diesel-rs/diesel · error · syn::Error

this derive can only be used on non-unit structs

Error message

this derive can only be used on non-unit structs

What it means

Diesel struct-mapping derives require named or tuple structs with at least one field; unit structs carry no fields and thus cannot map to table columns. `from_item` in model.rs raises this error at the mixed_site span when the input is not a struct with fields (or is a unit struct while `allow_unit_structs` is false).

Solutions

  1. Give the struct at least one field corresponding to a table column.
  2. Remove the diesel derive if the type is only a marker.
  3. If mapping a single column, use a tuple/newtype struct with a field, not a unit struct.

Example fix

// before
#[derive(Queryable)]
struct UserId;

// after
#[derive(Queryable)]
struct UserId(#[diesel(column_name = id)] i32);
Defensive patterns

Strategy: validation

Validate before calling

// Diesel struct derives need a struct with fields:
// struct Good { id: i32 }        // OK
// struct Good(i32);              // OK (tuple fields need column_name)
// struct Unit;                   // FAILS
// let _ = std::mem::size_of::<T>(); // companion check: unit structs compile but derive-fail

Prevention

When it happens

Trigger: Deriving `Queryable`, `Identifiable`, `Associations`, `Insertable`, etc. on a unit struct like `struct User;`, or on an enum/union where the derive doesn't accept it.

Common situations: Marker/phantom types accidentally carrying diesel derives; refactoring a struct to `struct X;` leaving derives behind; applying a struct derive to an enum.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07). Data as JSON: /api/errors/ba41a4b6739e87fb. Report an issue: GitHub.

Appendix: source

Thrown at diesel_derives/src/model.rs:61

        item: &DeriveInput,
        allow_unit_structs: bool,
        allow_multiple_table: bool,
    ) -> Result<Self> {
        let DeriveInput {
            data, ident, attrs, ..
        } = item;

        let fields = match *data {
            Data::Struct(DataStruct {
                fields: Fields::Named(FieldsNamed { ref named, .. }),
                ..
            }) => Some(named),
            Data::Struct(DataStruct {
                fields: Fields::Unnamed(FieldsUnnamed { ref unnamed, .. }),
                ..
            }) => Some(unnamed),
            _ if !allow_unit_structs => {
                return Err(syn::Error::new(
                    proc_macro2::Span::mixed_site(),
                    "this derive can only be used on non-unit structs",
                ));
            }
            _ => None,
        };

        let mut table_names = vec![];
        let mut primary_key_names = vec![Ident::new("id", Span::mixed_site())];
        let mut treat_none_as_default_value = None;
        let mut treat_none_as_null = None;
        let mut belongs_to = vec![];
        let mut sql_types = vec![];
        let mut aggregate = false;
        let mut not_sized = false;
        let mut enum_type = false;
        let mut foreign_derive = false;
        let mut mysql_type = None;

View on GitHub (pinned to 6fa6ed01b2)