PyO3/pyo3 · error · syn::Error

`set` may only be specified once

Error message

`set` may only be specified once

What it means

The pyo3 attribute parser rejects a `set` option specified more than once on the same pyclass field. Like `get`, the option is stored once in an Option slot; a second occurrence triggers this syn::Error at the duplicate keyword's span.

Source

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

impl FieldPyO3Options {
    fn take_pyo3_options(attrs: &mut Vec<syn::Attribute>) -> Result<Self> {
        let mut options = FieldPyO3Options {
            get: None,
            set: None,
            name: None,
        };

        for option in take_pyo3_options(attrs)? {
            match option {
                FieldPyO3Option::Get(kw) => {
                    if options.get.replace(Annotated::Field(kw)).is_some() {
                        return Err(syn::Error::new(kw.span(), UNIQUE_GET));
                    }
                }
                FieldPyO3Option::Set(kw) => {
                    if options.set.replace(Annotated::Field(kw)).is_some() {
                        return Err(syn::Error::new(kw.span(), UNIQUE_SET));
                    }
                }
                FieldPyO3Option::Name(name) => {
                    if options.name.replace(name).is_some() {
                        return Err(syn::Error::new(options.name.span(), UNIQUE_NAME));
                    }
                }
            }
        }

        Ok(options)
    }
}

fn get_class_python_name<'a>(cls: &'a Ident, args: &'a PyClassArgs) -> Cow<'a, Ident> {
    args.options
        .name
        .as_ref()

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Delete the duplicate `set` keyword, keeping a single occurrence per field
  2. If combining attribute fragments, de-duplicate options first
  3. Verify any macro wrappers don't add `set` unconditionally

Example fix

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

Strategy: validation

Validate before calling

// grep-style pre-commit check for duplicated pyo3 options
count_occurrences("#[pyo3(") line, "set") <= 1 per attribute

Prevention

When it happens

Trigger: A field annotated with `#[pyo3(set, set)]` or otherwise receiving the `set` keyword twice through merged/concatenated attribute lists.

Common situations: Copy-paste duplication when adding setters, refactor conflicts, or code generators appending `set` to attributes that already contain it.

Related errors


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