{"record":{"id":"aba62d99c1d60ce6","repo":"pola-rs/polars","slug":"validity-must-be-equal-to-the-array-s-length","errorCode":null,"errorMessage":"validity must be equal to the array's length","messagePattern":"validity must be equal to the array's length","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-arrow/src/array/binview/mod.rs","lineNumber":479,"sourceCode":"    impl_into_array!();\n\n    /// Returns this array with a new validity.\n    /// # Panic\n    /// Panics iff `validity.len() != self.len()`.\n    #[must_use]\n    #[inline]\n    pub fn with_validity(mut self, validity: Option<Bitmap>) -> Self {\n        self.set_validity(validity);\n        self\n    }\n\n    /// Sets the validity of this array.\n    /// # Panics\n    /// This function panics iff `values.len() != self.len()`.\n    #[inline]\n    pub fn set_validity(&mut self, validity: Option<Bitmap>) {\n        if matches!(&validity, Some(bitmap) if bitmap.len() != self.len()) {\n            panic!(\"validity must be equal to the array's length\")\n        }\n        self.total_bytes_len.store(UNKNOWN_LEN);\n        self.validity = validity;\n    }\n\n    /// Takes the validity of this array, leaving it without a validity mask.\n    #[inline]\n    pub fn take_validity(&mut self) -> Option<Bitmap> {\n        self.total_bytes_len.store(UNKNOWN_LEN);\n        self.validity.take()\n    }\n\n    pub fn from_slice<S: AsRef<T>, P: AsRef<[Option<S>]>>(slice: P) -> Self {\n        let mutable = MutableBinaryViewArray::from_iterator(\n            slice.as_ref().iter().map(|opt_v| opt_v.as_ref()),\n        );\n        mutable.into()\n    }","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/pola-rs/polars/blob/9b5d73fd00236295624374b075d16b1fe6ec6df9/crates/polars-arrow/src/array/binview/mod.rs#L461-L497","documentation":"Compile-time panic from the #[polars_expr] procedural macro in pyo3-polars-derive (create_expression_function, lib.rs:110). The macro walks the annotated function's parameters after the first one (the inputs slice) and requires every remaining parameter to be a normal typed argument (syn::FnArg::Typed). It panics with \"expected a type argument\" when a parameter in that position is instead a self receiver: self, &self, &mut self, mut self, or self: SomeType. syn parses receivers in any position, so such a signature reaches the macro before rustc rejects it.","triggerScenarios":"Annotating a function with #[polars_expr] where any parameter after the first is a receiver, e.g. fn my_expr(inputs: &[Series], &self, kwargs: MyKwargs) -> PolarsResult<Series>, or fn my_expr(inputs: &[Series], self: PluginCtx). Typically happens when an impl-block method body is pasted under the macro without stripping the receiver, or when converting a method-based API into a Polars plugin entry point.","commonSituations":"Porting a method from an impl block into an expression plugin crate; copy-pasting example code that used methods; refactoring older pyo3-polars plugin code where the calling convention differed; misunderstanding that #[polars_expr] must sit on a free function, not a method.","solutions":["Remove the self/&self/&mut self/self: Type parameter so every parameter after the first is a plain typed argument","Move the function out of the impl block: #[polars_expr] must annotate a free function, not a method","Keep the canonical shape: first parameter inputs: &[Series] (any name), optionally followed by context: CallerContext and/or kwargs: YourKwargsStruct","Run cargo check on the plugin crate to confirm the macro expands cleanly before writing the Python registration side"],"exampleFix":"// before — receiver left in the parameter list\n#[polars_expr(output_type=Int64)]\nfn my_expr(inputs: &[Series], &self) -> PolarsResult<Series> {\n    todo!()\n}\n\n// after — free function with plain typed parameters only\n#[polars_expr(output_type=Int64)]\nfn my_expr(inputs: &[Series]) -> PolarsResult<Series> {\n    todo!()\n}","handlingStrategy":"validation","validationCode":"# ci/check_polars_expr.py — run before cargo build\nimport re, sys, pathlib\npat = re.compile(r\"#\\[polars_expr\\([^)]*\\)\\]\\s*(?:pub\\s+)?fn\\s+\\w+\\(([^)]*)\\)\", re.S)\nfor f in pathlib.Path(\"src\").rglob(\"*.rs\"):\n    for m in pat.finditer(f.read_text()):\n        params = [p.strip() for p in m.group(1).split(\",\") if p.strip()]\n        if any(\"self\" in p.split(\":\")[0] for p in params[1:]):\n            sys.exit(f\"{f}: polars_expr fn has a `self` receiver in its parameters: {params}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never annotate impl-block methods with #[polars_expr]; plugin entry points are free functions","After pasting a method body into a plugin, delete the receiver before compiling","Keep a known-good plugin function in the crate as a template and start new ones from it"],"tags":["rust","proc-macro","polars","compile-time","function-signature"],"backgroundTag":"proc-macro-panicked","analyzedSha":"9b5d73fd00236295624374b075d16b1fe6ec6df9","analyzedAt":"2026-08-19T12:15:06.350Z","contentChangedAt":"2026-08-19T12:15:06.350Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}