{"record":{"id":"5372db80f390deac","repo":"neon-bindings/neon","slug":"in-classes-must-take-self-by-value-not-self-or-mut-self","errorCode":null,"errorMessage":"{} in classes must take `self` by value, not `&self` or `&mut self`. {}","messagePattern":"(.+?) in classes must take `self` by value, not `&self` or `&mut self`\\. (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon-macros/src/class/mod.rs","lineNumber":563,"sourceCode":"        ));\n    }\n\n    // Validate that async fn and task methods take self by value\n    if matches!(meta.kind, meta::Kind::AsyncFn | meta::Kind::Task) {\n        if let Some(syn::FnArg::Receiver(receiver)) = sig.inputs.first() {\n            if receiver.reference.is_some() {\n                // This is &self or &mut self, but we need self by value\n                let method_type = if matches!(meta.kind, meta::Kind::AsyncFn) {\n                    \"Async functions\"\n                } else {\n                    \"Task methods\"\n                };\n                let reason = if matches!(meta.kind, meta::Kind::AsyncFn) {\n                    \"This is required because async functions capture `self` in the Future, which must be `'static` for spawning.\"\n                } else {\n                    \"Since the instance is cloned before moving to the worker thread, taking `&self` would operate on a temporary reference to the clone, which is misleading.\"\n                };\n                return Err(syn::Error::new(\n                    receiver.span(),\n                    format!(\n                        \"{} in classes must take `self` by value, not `&self` or `&mut self`. {}\",\n                        method_type, reason\n                    ),\n                ));\n            }\n        } else {\n            let method_type = if matches!(meta.kind, meta::Kind::AsyncFn) {\n                \"Async functions\"\n            } else {\n                \"Task methods\"\n            };\n            return Err(syn::Error::new(\n                sig.span(),\n                format!(\n                    \"{} in classes must take `self` as their first parameter.\",\n                    method_type","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon-macros/src/class/mod.rs#L545-L581","documentation":"Async functions and `#[neon(task)]` methods in neon classes must take `self` by value (`self`), not `&self` or `&mut self`. The instance is cloned and moved to the worker thread, so a reference would point at a temporary clone — misleading at best and, for async futures (which must be `'static` for spawning), simply not allowed.","triggerScenarios":"Declaring a method as `async fn work(&self)` or `async fn work(&mut self)` inside a `#[neon] impl` block; declaring `#[neon(task)] fn run(&self)`; either receiver form trips this validation.","commonSituations":"Porting regular class methods (which freely use `&self`) to `async` or task form; writing idiomatic Rust receiver style out of habit; copying a sync method and only adding `async` without changing the receiver.","solutions":["Change the receiver from `&self`/`&mut self` to `self` (take ownership).","If you need mutation, perform the mutation before cloning, or restructure so the task owns its own data.","Clone any needed state inside the method body instead of borrowing it.","Convert back to a regular (non-async, non-task) method if borrowing is essential."],"exampleFix":"// before\n#[neon]\nimpl Counter {\n    async fn increment(&self, n: f64) -> JsResult<JsNumber> { ... }\n}\n\n// after\n#[neon]\nimpl Counter {\n    async fn increment(self, n: f64) -> JsResult<JsNumber> { ... }\n}","handlingStrategy":"validation","validationCode":"// Pre-check method shape before annotating\nfn assert_by_value_self(is_async_or_task: bool, receiver: Option<&str>) -> Result<(), String> {\n    if is_async_or_task && receiver.map(|r| r != \"self\").unwrap_or(false) {\n        return Err(\"async/task methods must take `self` by value\".into());\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default to `self` (not `&self`) for any async or #[neon(task)] class method.","Clone needed fields explicitly inside the method body instead of borrowing.","Read the macro's error reason: it explains the clone-before-move semantics."],"tags":["rust","neon","macros","async","self-receiver"],"backgroundTag":"invalid-argument-value","analyzedSha":"38960e4381d9ad13b551cdf2d261f609167c9bc2","analyzedAt":"2026-09-13T09:05:33.640Z","contentChangedAt":"2026-09-13T09:05:33.640Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}