diesel-rs/diesel · error

`embed` and `treat_none_as_default_value` are mutually…

Error message

`embed` and `treat_none_as_default_value` are mutually exclusive

What it means

In the `Insertable` derive, a field marked `#[diesel(embed)]` (splicing another table's columns in) cannot also set `treat_none_as_default_value`, since embedded fields don't map to a single column with a default. The check in derive_into_single_table rejects the combination at insertable.rs:61.

Solutions

  1. Remove `treat_none_as_default_value` from the embedded field (or from the struct level for that field).
  2. Apply `treat_none_as_default_value` only to plain `Option<T>` fields, not embedded ones.
  3. If you need default handling inside the embedded struct, set it within that nested type's own derive.

Example fix

// before
#[derive(Insertable)]
#[diesel(table_name = posts)]
struct NewPost {
  #[diesel(embed, treat_none_as_default_value = true)]
  meta: PostMeta,
}

// after
#[derive(Insertable)]
#[diesel(table_name = posts)]
struct NewPost {
  #[diesel(embed)]
  meta: PostMeta,
}
Defensive patterns

Strategy: validation

Validate before calling

// Never combine embed with treat_none_as_default_value on one field:
// #[diesel(embed)]                     // OK
// #[diesel(embed, treat_none_as_default_value = true)] // FAILS

Prevention

When it happens

Trigger: A struct-level or field-level `treat_none_as_default_value` attribute applied to a field that also has `#[diesel(embed)]`.

Common situations: Setting `treat_none_as_default_value` at the struct level while some fields embed nested insertables; copy-pasting option/default handling onto embedded fields.

Related errors


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

Appendix: source

Thrown at diesel_derives/src/insertable.rs:61

    let mut ref_field_ty = Vec::with_capacity(model.fields().len());
    let mut ref_field_assign = Vec::with_capacity(model.fields().len());

    // Explicit trait bounds to improve error messages
    let mut field_ty_bounds = Vec::with_capacity(model.fields().len());
    let mut borrowed_field_ty_bounds = Vec::with_capacity(model.fields().len());
    let mut field_ty_bounds_guard = HashMap::new();
    let mut borrowed_field_ty_bounds_guard = HashMap::new();

    for field in model.fields() {
        // skip this field while generating the insertion
        if field.skip_insertion() {
            continue;
        }
        // Use field-level attr. with fallback to the struct-level one.
        let treat_none_as_default_value = match &field.treat_none_as_default_value {
            Some(attr) => {
                if let Some(embed) = &field.embed {
                    return Err(syn::Error::new(
                        embed.attribute_span,
                        "`embed` and `treat_none_as_default_value` are mutually exclusive",
                    ));
                }

                if !is_option_ty(&field.ty) {
                    return Err(syn::Error::new(
                        field.ty.span(),
                        "expected `treat_none_as_default_value` field to be of type `Option<_>`",
                    ));
                }

                attr.item
            }
            None => treat_none_as_default_value,
        };

        match (field.serialize_as.as_ref(), field.embed()) {

View on GitHub (pinned to 6fa6ed01b2)