PyO3/pyo3 · error · syn::Error
`get` may only be specified once
Error message
`get` may only be specified once
What it means
pyo3's #[pyclass]/field attribute parser rejects a `get` option that appears more than once on the same item. Each field attribute option is stored in an Option slot; when a duplicate `get` keyword is parsed, the `replace` on the slot returns Some and the macro emits this syn::Error pointing at the duplicate keyword's span.
Source
Thrown at pyo3-macros-backend/src/pyclass.rs:402
} else {
Err(lookahead.error())
}
}
}
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)
}
}View on GitHub (pinned to ac9b6899d3)
Solutions
- Remove the duplicate `get` keyword so it appears at most once per field
- If two attribute lists are being merged, de-duplicate options before passing them to the macro
- Check macro-generated or wrapper code that may inject `get` automatically
Example fix
// before
#[pyclass]
struct Point {
#[pyo3(get, get)]
x: i32,
}
// after
#[pyclass]
struct Point {
#[pyo3(get)]
x: i32,
} Defensive patterns
Strategy: validation
Validate before calling
// Compile-time check: ensure each pyclass field lists each option once
fn validate_unique_options(attrs: &[&str]) -> Result<(), String> {
let mut seen = std::collections::HashSet::new();
for a in attrs {
if !seen.insert(a) { return Err(format!("duplicate option: {}", a)); }
}
Ok(())
} Prevention
- List each `get`/`set`/`name` option once per field
- When merging attribute fragments, de-duplicate first
- Run cargo check promptly after attribute edits — these fail at compile time
When it happens
Trigger: Compiling Rust code where a #[pyclass] field (or getter) declares `#[pyo3(get)]` (or `get` inside the macro args) twice, e.g. `#[pyo3(get, get)]` or a duplicated option spread across merged attribute lists.
Common situations: Copy-paste of attribute lines when adding getters/refactor merges that concatenate two attribute sets; macro-generated code that blindly appends `get` to an existing attribute list.
Related errors
- `set` may only be specified once
- `name` may only be specified once
- missing `message` in `warn` attribute
- Python doc may not contain nul byte, found nul at position {
- Neither abi3 or abi3t features are enabled
AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05).
Data as JSON: /api/errors/813060d8b94691ef.
Report an issue: GitHub.