{"record":{"id":"3cac6a99b389b75c","repo":"pola-rs/polars","slug":"could-not-unwrap-optional-zipvalidity-iterato","errorCode":null,"errorMessage":"Could not 'unwrap_optional'. 'ZipValidity' iterator has no nulls.","messagePattern":"Could not 'unwrap_optional'\\. 'ZipValidity' iterator has no nulls\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-arrow/src/bitmap/utils/zip_validity.rs","lineNumber":214,"sourceCode":"\nimpl<T, I, V> ZipValidity<T, I, V>\nwhere\n    I: Iterator<Item = T>,\n    V: Iterator<Item = bool>,\n{\n    /// Unwrap into an iterator that has no null values.\n    pub fn unwrap_required(self) -> I {\n        match self {\n            ZipValidity::Required(i) => i,\n            _ => panic!(\"Could not 'unwrap_required'. 'ZipValidity' iterator has nulls.\"),\n        }\n    }\n\n    /// Unwrap into an iterator that has null values.\n    pub fn unwrap_optional(self) -> ZipValidityIter<T, I, V> {\n        match self {\n            ZipValidity::Optional(i) => i,\n            _ => panic!(\"Could not 'unwrap_optional'. 'ZipValidity' iterator has no nulls.\"),\n        }\n    }\n}\n","sourceCodeStart":196,"sourceCodeEnd":218,"githubUrl":"https://github.com/pola-rs/polars/blob/9b5d73fd00236295624374b075d16b1fe6ec6df9/crates/polars-arrow/src/bitmap/utils/zip_validity.rs#L196-L218","documentation":"The inverse of unwrap_required: unwrap_optional() only works on ZipValidity::Optional (an iterator yielding Option<T>). Calling it on a Required value — built for an array without any validity — panics because there is no null information to attach.","triggerScenarios":"Calling unwrap_optional() on the ZipValidity produced when validity is None, e.g. generic code that unconditionally treats every iterator as nullable.","commonSituations":"A single code path written for both nullable and dense arrays with the dense case forgotten; arrays produced by a kernel that guarantees no validity (freshly built, never filtered).","solutions":["Branch on validity(): is_none() -> consume plain values; is_some() -> unwrap_optional()","If Option items are required for both cases, map the Required iterator with .map(Some)","Avoid unwrap_optional in generic code; keep the ZipValidity enum and match on it"],"exampleFix":"// before\nlet it = zip_validity(values, validity).unwrap_optional();\n\n// after\nlet it = match zip_validity(values, validity) {\n    ZipValidity::Optional(it) => it,\n    ZipValidity::Required(it) => it.map(Some),\n};","handlingStrategy":"validation","validationCode":"fn has_nulls(arr: &dyn polars_arrow::array::Array) -> bool {\n    arr.validity().is_some()\n}\n// only unwrap_optional when has_nulls(&arr); otherwise map items with Some","typeGuard":"fn can_unwrap_optional<T, I, V>(zv: &polars_arrow::bitmap::utils::ZipValidity<T, I, V>) -> bool {\n    matches!(zv, polars_arrow::bitmap::utils::ZipValidity::Optional(_))\n}","tryCatchPattern":null,"preventionTips":["Branch on validity() before unwrap_optional","Match on the ZipValidity enum instead of unwrapping a specific variant","In generic code, normalize with .map(Some) on the Required path"],"tags":["rust","polars","arrow","iterator","nulls"],"backgroundTag":"null-unwrapping","analyzedSha":"9b5d73fd00236295624374b075d16b1fe6ec6df9","analyzedAt":"2026-08-19T12:15:06.350Z","contentChangedAt":"2026-08-19T12:15:06.350Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}