diesel-rs/diesel · error
deriving `AsChangeset` on a structure that only contains…
Error message
deriving `AsChangeset` on a structure that only contains primary keys isn't supported. help: if you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`. note: `#[derive(AsChangeset)]` never changes the primary key of a row.
What it means
`#[derive(AsChangeset)]` builds the set of columns to update from the struct's non-primary-key fields. If after removing primary-key fields nothing remains, the derive cannot generate a meaningful changeset and refuses to compile, explaining that primary keys are never changed by this derive.
Solutions
- Add at least one non-primary-key field to the struct
- Remove the `AsChangeset` derive and use `.set(table::id.eq(new_id))` directly to change the primary key
- Use `dsl::UpdateTarget`/`update(...).set(...)` manually instead of the derive
Example fix
// before
#[derive(AsChangeset)]
struct UserPk { id: i32 }
// after — change PK directly
diesel::update(users.find(id)).set(users.id.eq(new_id)) Defensive patterns
Strategy: validation
Validate before calling
// Before deriving, ensure at least one field is not a primary key let non_pk = fields.iter().filter(|f| !is_primary_key(f)).count(); assert!(non_pk > 0, "AsChangeset requires at least one non-PK field");
Prevention
- Only derive AsChangeset on structs with updatable columns
- Change primary keys with `.set(table::id.eq(new_id))` instead
- Don't put AsChangeset on ID-only wrapper structs
When it happens
Trigger: Deriving `AsChangeset` on a struct where every field is annotated as (or resolves to) the table's primary key, so `fields_for_update` is empty.
Common situations: A struct representing just a row's ID(s) (e.g. `struct UserId { id: i32 }`); structs whose only column is the PK after renames via `#[column_name]`.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 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/b49864551321b3d5.
Report an issue: GitHub.
Appendix: source
Thrown at diesel_derives/src/as_changeset.rs:31
pub fn derive(item: DeriveInput) -> Result<TokenStream> {
let model = Model::from_item(&item, false, false)?;
let struct_name = &item.ident;
let table_name = &model.table_names()[0];
let fields_for_update = model
.fields()
.iter()
.filter(|f| {
!model
.primary_key_names
.iter()
.any(|p| f.column_name().map(|f| f == *p).unwrap_or_default())
})
.collect::<Vec<_>>();
if fields_for_update.is_empty() {
return Err(syn::Error::new(
proc_macro2::Span::mixed_site(),
"deriving `AsChangeset` on a structure that only contains primary keys isn't supported.\n\
help: if you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`.\n\
note: `#[derive(AsChangeset)]` never changes the primary key of a row.",
));
}
let treat_none_as_null = model.treat_none_as_null();
let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
let mut generate_borrowed_changeset = true;
let mut direct_field_ty = Vec::with_capacity(fields_for_update.len());
let mut direct_field_assign = Vec::with_capacity(fields_for_update.len());
let mut ref_field_ty = Vec::with_capacity(fields_for_update.len());
let mut ref_field_assign = Vec::with_capacity(fields_for_update.len());
View on GitHub (pinned to 6fa6ed01b2)