diesel-rs/diesel · error
expected `treat_none_as_null` field to be of type `Option
Error message
expected `treat_none_as_null` field to be of type `Option<_>`
What it means
When a field has `treat_none_as_null`, the derive must be able to represent `None` in that field's Rust type, which requires `Option<T>`. If the field's type is not an `Option<_>`, the derive fails at the field's type span, since there is no `None` value to translate to NULL.
Solutions
- Change the field type to `Option<T>`
- Remove the `treat_none_as_null` attribute if the field cannot be null
- Use `treat_none_as_default_value` semantics or handle defaults instead if appropriate
Example fix
// before #[diesel(treat_none_as_null)] nickname: String, // after #[diesel(treat_none_as_null)] nickname: Option<String>,
Defensive patterns
Strategy: type-guard
Type guard
fn is_option_ty(t: &syn::Type) -> bool {
if let syn::Type::Path(p) = t {
p.path.segments.last().map_or(false, |s| s.ident == "Option")
} else { false }
} Prevention
- Only annotate `Option<T>` fields with `treat_none_as_null`
- Remove the attribute if the field type is not Optional
- Check fields after type refactors for stale null-handling attributes
When it happens
Trigger: Annotating a non-Option field with `#[diesel(treat_none_as_null)]`, e.g. `#[diesel(treat_none_as_null)] name: String`.
Common situations: Adding the attribute to make NULL handling explicit but forgetting to wrap the field type in `Option`; refactoring a field from `Option<T>` to `T` while keeping the attribute.
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
- expected attribute `name` help: the correct format looks…
- unknown attribute, expected
- unexpected end of input, expected `=` help: the correct…
- expected type
- unexpected end of input, expected parentheses help: the…
AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07).
Data as JSON: /api/errors/f85a7ddfd3825d1c.
Report an issue: GitHub.
Appendix: source
Thrown at diesel_derives/src/as_changeset.rs:72
let mut borrowed_field_ty_bounds_guard = HashMap::new();
for field in fields_for_update {
// skip this field while generating the update
if field.skip_update() {
continue;
}
// Use field-level attr. with fallback to the struct-level one.
let treat_none_as_null = match &field.treat_none_as_null {
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_null` field to be of type `Option<_>`",
));
}
attr.item
}
None => treat_none_as_null,
};
match (field.serialize_as.as_ref(), field.embed()) {
(Some(AttributeSpanWrapper { item: ty, .. }), false) => {
direct_field_ty.push(field_changeset_ty_serialize_as(
field,
table_name,
ty,
treat_none_as_null,
)?);View on GitHub (pinned to 6fa6ed01b2)