{"record":{"id":"fa58fa65d9106e0e","repo":"pola-rs/polars","slug":"python-function-should-return-list-str","errorCode":null,"errorMessage":"python function should return List[str]","messagePattern":"python function should return List\\[str\\]","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-python/src/lazyframe/general.rs","lineNumber":292,"sourceCode":"            .with_glob(glob)\n            .with_raise_if_empty(raise_if_empty)\n            .with_include_file_paths(include_file_paths.map(|x| x.into()))\n            .with_missing_columns_policy(missing_columns.map(|x| x.0));\n\n        if let Some(new_columns) = new_columns {\n            r = r.with_column_names_overwrite(new_columns.0);\n        }\n\n        if let Some(lambda) = with_schema_modify {\n            let f = |schema: Schema| {\n                let iter = schema.iter_names().map(|s| s.as_str());\n                Python::attach(|py| {\n                    let names = PyList::new(py, iter).unwrap();\n\n                    let out = lambda.call1(py, (names,)).expect(\"python function failed\");\n                    let new_names = out\n                        .extract::<Vec<String>>(py)\n                        .expect(\"python function should return List[str]\");\n                    polars_ensure!(new_names.len() == schema.len(),\n                        ShapeMismatch: \"The length of the new names list should be equal to or less than the original column length\",\n                    );\n                    Ok(schema\n                        .iter_values()\n                        .zip(new_names)\n                        .map(|(dtype, name)| Field::new(name.into(), dtype.clone()))\n                        .collect())\n                })\n            };\n            r = r.with_schema_modify(f).map_err(PyPolarsErr::from)?\n        }\n\n        Ok(r.finish().map_err(PyPolarsErr::from)?.into())\n    }\n\n    #[cfg(feature = \"parquet\")]\n    #[staticmethod]","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/crates/polars-python/src/lazyframe/general.rs#L274-L310","documentation":"After the with_schema_modify callback runs, its return value is extracted as Vec<String>. If the callable returns anything else (list of bytes, a single string, a dict, None), extraction fails and this expect panics with 'python function should return List[str]'. A separate, proper polars error is raised only later if the length mismatches the schema.","triggerScenarios":"Callbacks returning List[bytes] (e.g. [n.encode() for n in names]), a generator, a tuple, a numpy array of objects, or a plain string instead of a list of str, passed as with_schema_modify to a lazy scan.","commonSituations":"Encoding renames for a different API, returning map(names) results from a function that yields non-strings, pandas-flavored callbacks returning an Index.","solutions":["Return a plain list of str with exactly one entry per input name","Wrap generators/comprehensions with list(...) and ensure each element is a str","Annotate the callback as Callable[[list[str]], list[str]] and test it standalone","Check the length matches the input; mismatch triggers a separate ShapeMismatch error"],"exampleFix":"# before\nrename = lambda names: [n.encode() for n in names]  # list[bytes] -> panic\n\n# after\nrename = lambda names: [str(n).lower() for n in names]  # list[str]","handlingStrategy":"type-guard","validationCode":"out = rename(names)\nassert type(out) is list, \"must return list, not generator/tuple/str\"\nassert all(isinstance(n, str) for n in out), \"elements must be str, not bytes\"","typeGuard":"def returns_str_list(f, names: list[str]) -> bool:\n    out = f(list(names))\n    return isinstance(out, list) and len(out) == len(names) and all(type(n) is str for n in out)","tryCatchPattern":null,"preventionTips":["Wrap generator expressions with list(...)","Type-annotate callbacks Callable[[list[str]], list[str]]","Return str(n) for any element that may not be str"],"tags":["python","lazyframe","schema","type-error","callback","panic"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}