{"record":{"id":"f85a7ddfd3825d1c","repo":"diesel-rs/diesel","slug":"expected-treat-none-as-null-field-to-be-of-type","errorCode":null,"errorMessage":"expected `treat_none_as_null` field to be of type `Option<_>`","messagePattern":"expected `treat_none_as_null` field to be of type `Option<_>`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"diesel_derives/src/as_changeset.rs","lineNumber":72,"sourceCode":"    let mut borrowed_field_ty_bounds_guard = HashMap::new();\n\n    for field in fields_for_update {\n        // skip this field while generating the update\n        if field.skip_update() {\n            continue;\n        }\n        // Use field-level attr. with fallback to the struct-level one.\n        let treat_none_as_null = match &field.treat_none_as_null {\n            Some(attr) => {\n                if let Some(embed) = &field.embed {\n                    return Err(syn::Error::new(\n                        embed.attribute_span,\n                        \"`embed` and `treat_none_as_default_value` are mutually exclusive\",\n                    ));\n                }\n\n                if !is_option_ty(&field.ty) {\n                    return Err(syn::Error::new(\n                        field.ty.span(),\n                        \"expected `treat_none_as_null` field to be of type `Option<_>`\",\n                    ));\n                }\n\n                attr.item\n            }\n            None => treat_none_as_null,\n        };\n\n        match (field.serialize_as.as_ref(), field.embed()) {\n            (Some(AttributeSpanWrapper { item: ty, .. }), false) => {\n                direct_field_ty.push(field_changeset_ty_serialize_as(\n                    field,\n                    table_name,\n                    ty,\n                    treat_none_as_null,\n                )?);","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/diesel-rs/diesel/blob/6fa6ed01b24b24248ab2a611698d0a7c6a2e9120/diesel_derives/src/as_changeset.rs#L54-L90","documentation":"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.","triggerScenarios":"Annotating a non-Option field with `#[diesel(treat_none_as_null)]`, e.g. `#[diesel(treat_none_as_null)] name: String`.","commonSituations":"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.","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"],"exampleFix":"// before\n#[diesel(treat_none_as_null)]\nnickname: String,\n// after\n#[diesel(treat_none_as_null)]\nnickname: Option<String>,","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn is_option_ty(t: &syn::Type) -> bool {\n    if let syn::Type::Path(p) = t {\n        p.path.segments.last().map_or(false, |s| s.ident == \"Option\")\n    } else { false }\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","diesel","proc-macro","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"6fa6ed01b24b24248ab2a611698d0a7c6a2e9120","analyzedAt":"2026-09-07T01:50:13.074Z","contentChangedAt":"2026-09-07T01:50:13.074Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}