pola-rs/polars · error
invalid value for POLARS_PYTHON_SCAN_RESOLVE_THREADS: {x}
Error message
invalid value for POLARS_PYTHON_SCAN_RESOLVE_THREADS: {x} What it means
Polars reads the environment variable POLARS_PYTHON_SCAN_RESOLVE_THREADS once, when lazily initializing the Python scan-resolve thread pool, and requires it to parse as a non-zero usize. Any other value (empty string, non-numeric, 0) aborts initialization with this panic. Valid values control how many threads the scan resolution thread pool uses (default 128).
Source
Thrown at crates/polars-utils/src/python_thread_pool.rs:31
type Output = <&'py Py<PyAny> as IntoPyObject<'py>>::Output;
type Target = <&'py Py<PyAny> as IntoPyObject<'py>>::Target;
type Error = <&'py Py<PyAny> as IntoPyObject<'py>>::Error;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
IntoPyObject::into_pyobject(&self.0, py)
}
}
impl PyThreadPool {
pub fn new() -> Self {
use std::num::NonZeroUsize;
Python::attach(|py| {
let num_threads =
std::env::var("POLARS_PYTHON_SCAN_RESOLVE_THREADS").map_or(128, |x| {
x.parse::<NonZeroUsize>()
.unwrap_or_else(|_| {
panic!("invalid value for POLARS_PYTHON_SCAN_RESOLVE_THREADS: {x}")
})
.get()
});
if polars_config::config().verbose() {
eprintln!("python scan_resolve_threadpool threads: {num_threads}")
}
return Self(
py_scan_resolve_threadpool_cls(py)
.bind(py)
.call1((num_threads,))
.map(|x| x.unbind())
.unwrap(),
);
fn py_scan_resolve_threadpool_cls(py: Python<'_>) -> &'static Py<PyAny> {
static CLS: PyOnceLock<Py<PyAny>> = PyOnceLock::new();View on GitHub (pinned to 68506541d2)
Solutions
- Unset POLARS_PYTHON_SCAN_RESOLVE_THREADS to fall back to the default of 128.
- Set it to a plain positive integer, e.g. `export POLARS_PYTHON_SCAN_RESOLVE_THREADS=64`.
- Remove surrounding whitespace/quotes/BOM from the value in shell profiles, .env files, or k8s manifests.
- Ensure the value is set before the Polars process starts; if set programmatically, set it via os.environ before the first scan.
Example fix
// before POLARS_PYTHON_SCAN_RESOLVE_THREADS=0 // after POLARS_PYTHON_SCAN_RESOLVE_THREADS=64
Defensive patterns
Strategy: validation
Validate before calling
import os, re
v = os.environ.get("POLARS_PYTHON_SCAN_RESOLVE_THREADS")
if v is not None and not (v.strip().isdigit() and int(v) > 0):
raise ValueError(f"POLARS_PYTHON_SCAN_RESOLVE_THREADS must be a positive integer, got {v!r}") Type guard
def is_valid_thread_count(v: str | None) -> bool:
return v is None or (v.strip().isdigit() and int(v) > 0) Prevention
- Only set plain positive integers in env config
- Sanitize env values (strip whitespace/quotes) in deployment manifests
- Document that 0 is invalid — omit the variable for defaults
- Validate env config at process startup, before the first scan
When it happens
Trigger: Setting POLARS_PYTHON_SCAN_RESOLVE_THREADS in the environment or process env to anything not parseable by `usize::from_str` as a NonZeroUsize — e.g. `"0"`, `""`, `"abc"`, `"12.5"`, `"1_000"` — and then executing the first Python-scan operation that initializes the pool.
Common situations: Copy-pasted config with typos, quoting artifacts from shell profiles or container orchestration env files (`THREADS=128\n`), setting 0 assuming it means 'unlimited', unit suffixes like `128k`, or locale-formatted numbers.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
Related errors
- Invalid `POLARS_PQ_PREFILTERED_MASK` value '{v}'.
- not implemented
- length to fit in `usize`
- offset to fit in `usize`
- Offset to fit in `usize`
AI-assisted analysis of pola-rs/polars@68506541d2 (2026-09-10).
Data as JSON: /api/errors/260024f2ee96f53f.
Report an issue: GitHub.