diesel-rs/diesel · error
`#[diesel(embed)]` cannot be combined with…
Error message
`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`
What it means
The `AsChangeset` derive in diesel rejects a struct field annotated with both `#[diesel(embed)]` and `#[diesel(serialize_as)]`. `embed` inlines a nested struct's fields, while `serialize_as` converts the field to a different Rust type for serialization; the generated code cannot combine both transformations, so the derive emits a compile error pointing at the field's `serialize_as` attribute span.
Solutions
- Remove `#[diesel(serialize_as)]` from the embedded field and apply `serialize_as` on the inner struct's own fields instead.
- Remove `#[diesel(embed)]` if the field genuinely needs type conversion during updates.
- Split the struct: keep the embedded value object separate from the converted field.
Example fix
// before
#[derive(AsChangeset)]
struct UserChangeset {
#[diesel(embed)]
#[diesel(serialize_as = "String")]
name: MyNameWrapper,
}
// after
#[derive(AsChangeset)]
struct UserChangeset {
#[diesel(embed)]
name: NameFields,
} Defensive patterns
Strategy: validation
Validate before calling
// Attribute audit before compiling
fn validate_field_attrs(attrs: &[&str]) -> Result<(), String> {
let has_embed = attrs.iter().any(|a| a.contains("embed"));
let has_serialize_as = attrs.iter().any(|a| a.contains("serialize_as"));
if has_embed && has_serialize_as {
return Err("a field cannot use both #[diesel(embed)] and #[diesel(serialize_as)]".into());
}
Ok(())
} Prevention
- Keep `serialize_as` on leaf fields only; use `embed` for whole nested structs
- When adding `#[diesel(embed)]` to a field, grep its existing attribute block for `serialize_as`
- Run `cargo check` immediately after attribute refactors
When it happens
Trigger: Deriving `AsChangeset` (usually via `#[derive(AsChangeset)]` or `AsChangeset` pulled in through `ActiveModel`-style patterns) on a struct where the same field carries both `#[diesel(embed)]` and `#[diesel(serialize_as = "...")]`.
Common situations: Developers copy a field's `serialize_as` from a pre-embed version of the struct, then add `embed` to inline a nested struct without removing the old attribute; refactoring structs to nest value objects while keeping old conversion annotations.
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
- at least one `sql_type` is needed for deriving…
- at least one `belongs_to` is needed for deriving…
- this derive can only be used on enums with exclusively…
- expected a literal expression, but got something else
- not implemented
AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07).
Data as JSON: /api/errors/26902b3ca98eda4a.
Report an issue: GitHub.
Appendix: source
Thrown at diesel_derives/src/as_changeset.rs:109
direct_field_assign.push(field_changeset_expr_serialize_as(
field,
table_name,
ty,
treat_none_as_null,
)?);
field_ty_bounds.push(generate_field_bound(
field,
table_name,
Some(ty),
None,
&mut field_ty_bounds_guard,
treat_none_as_null,
)?);
generate_borrowed_changeset = false; // as soon as we hit one field with #[diesel(serialize_as)] there is no point in generating the impl of AsChangeset for borrowed structs
}
(Some(AttributeSpanWrapper { attribute_span, .. }), true) => {
return Err(syn::Error::new(
*attribute_span,
"`#[diesel(embed)]` cannot be combined with `#[diesel(serialize_as)]`",
));
}
(None, true) => {
direct_field_ty.push(field_changeset_ty_embed(field, None));
direct_field_assign.push(field_changeset_expr_embed(field, None));
ref_field_ty.push(field_changeset_ty_embed(field, Some(quote!(&'update))));
ref_field_assign.push(field_changeset_expr_embed(field, Some(quote!(&))));
}
(None, false) => {
direct_field_ty.push(field_changeset_ty(
field,
table_name,
None,
treat_none_as_null,
)?);
direct_field_assign.push(field_changeset_expr(View on GitHub (pinned to 6fa6ed01b2)