PyO3/pyo3 · error · syn::Error

useless `set` - the struct is already annotated with `set_al

Error message

useless `set` - the struct is already annotated with `set_all`

What it means

Compile-time syn error emitted while merging per-field options for #[pyclass]: a field (or the struct) carries an explicit `set` annotation, but the struct is already annotated with `set_all`, which already covers setters for all fields. The redundant `set` is rejected as useless rather than silently ignored, and the span points at the conflicting annotation.

Source

Thrown at pyo3-macros-backend/src/pyclass.rs:340

            results
        }
    }
    .into_iter()
    .try_combine_syn_errors()?;

    if let Some(attr) = args.options.get_all {
        for (_, FieldPyO3Options { get, .. }) in &mut field_options {
            if let Some(old_get) = get.replace(Annotated::Struct(attr)) {
                return Err(syn::Error::new(old_get.span(), DUPE_GET));
            }
        }
    }

    if let Some(attr) = args.options.set_all {
        for (_, FieldPyO3Options { set, .. }) in &mut field_options {
            if let Some(old_set) = set.replace(Annotated::Struct(attr)) {
                return Err(syn::Error::new(old_set.span(), DUPE_SET));
            }
        }
    }

    impl_class(&class.ident, &args, doc, field_options, methods_type, ctx)
}

enum Annotated<X, Y> {
    Field(X),
    Struct(Y),
}

impl<X: Spanned, Y: Spanned> Annotated<X, Y> {
    fn span(&self) -> Span {
        match self {
            Self::Field(x) => x.span(),
            Self::Struct(y) => y.span(),
        }

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Remove the per-field #[pyo3(set)] attributes where set_all already applies
  2. Remove set_all if only selected fields should be writable
  3. Keep explicit per-field set annotations only for fields needing special handling and drop set_all

Example fix

// before
#[pyclass(set_all)]
struct Point {
    #[pyo3(set)]
    x: f64,
    y: f64,
}
// after
#[pyclass(set_all)]
struct Point {
    x: f64,
    y: f64,
}
Defensive patterns

Strategy: validation

Validate before calling

# CI lint: flag #[pyo3(set)] inside structs whose pyclass has set_all
# grep -A2 'pyclass(.*set_all' -r src/ | grep 'pyo3(set)' && exit 1

Prevention

When it happens

Trigger: Combining #[pyclass(set_all)] with #[pyo3(set)] on one or more fields of the struct.

Common situations: Migrating individual #[pyo3(set)] attributes to set_all without cleanup; template/copy-paste mistakes when adding set_all.

Related errors


AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05). Data as JSON: /api/errors/979dc80974c4868b. Report an issue: GitHub.