pola-rs/polars · error
integer
Error message
integer
What it means
get_semaphore initializes a global concurrency semaphore once; if POLARS_CONCURRENCY_BUDGET is set but does not parse as usize, expect("integer") panics. The whole process aborts because the budget must be a plain positive integer.
Solutions
- Set POLARS_CONCURRENCY_BUDGET to a plain positive integer, e.g. POLARS_CONCURRENCY_BUDGET=16.
- Strip whitespace/quotes from wherever the variable is exported.
- Unset the variable entirely to fall back to the default (rayon threads, min max-per-request).
- Use POLARS_MAX_THREADS instead if you wanted to control thread count rather than the semaphore budget.
Example fix
// before POLARS_CONCURRENCY_BUDGET=12.0 // after POLARS_CONCURRENCY_BUDGET=12
Defensive patterns
Strategy: validation
Validate before calling
if let Ok(v) = std::env::var("POLARS_CONCURRENCY_BUDGET") {
let parsed = v.trim().parse::<usize>();
assert!(parsed.is_ok(), "POLARS_CONCURRENCY_BUDGET must be a positive integer, got {v:?}");
} Type guard
fn valid_budget(v: &str) -> bool { v.trim().parse::<usize>().is_ok() } Try / catch
// expect() panics; validate the env var at process startup before any polars call
std::env::var("POLARS_CONCURRENCY_BUDGET")
.ok()
.filter(|v| !valid_budget(v))
.map(|bad| panic!("fix POLARS_CONCURRENCY_BUDGET={bad:?}: must be an integer")); Prevention
- Set POLARS_CONCURRENCY_BUDGET as a bare integer (no %, units, decimals, spaces)
- Validate deployment env files in CI so bad values never reach runtime
- Prefer unsetting the var to use defaults if unsure of a value
When it happens
Trigger: Setting POLARS_CONCURRENCY_BUDGET to a non-integer value (e.g. "16.0", "abc", "", "8 ", negative like "-4") before any call that reaches get_concurrency_limit, tune_with_concurrency_budget, or with_concurrency_budget.
Common situations: Setting the env var to '50%' or 'default' in CI scripts; quoting issues adding whitespace/newlines; setting it in .env files with surrounding spaces; expecting a float fraction of cores.
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
- could not spawn threads
- error initializing temporary directory
- finish_open: could not acquire shared lock on data file at
- invalid value for POLARS_MAX_CONCURRENT_SCANS
- invalid value for POLARS_PARTITIONED_UPLOAD_CONCURRENCY
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/667948e08d47cfcf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/polars-io/src/pl_async.rs:148
}
},
Optimization::Finished => {},
}
self.last_tune = std::time::Instant::now();
// Not finished.
false
}
}
static INCR: RelaxedCell<u64> = RelaxedCell::new_u64(0);
static FINISHED_TUNING: RelaxedCell<bool> = RelaxedCell::new_bool(false);
static PERMIT_STORE: std::sync::OnceLock<tokio::sync::RwLock<SemaphoreTuner>> =
std::sync::OnceLock::new();
fn get_semaphore() -> &'static (Semaphore, u32) {
CONCURRENCY_BUDGET.get_or_init(|| {
let permits = std::env::var("POLARS_CONCURRENCY_BUDGET")
.map(|s| {
let budget = s.parse::<usize>().expect("integer");
FINISHED_TUNING.store(true);
budget
})
.unwrap_or_else(|_| std::cmp::max(RAYON.current_num_threads(), MAX_BUDGET_PER_REQUEST));
(Semaphore::new(permits), permits as u32)
})
}
pub fn get_concurrency_limit() -> u32 {
get_semaphore().1
}
pub async fn tune_with_concurrency_budget<F, Fut>(requested_budget: u32, callable: F) -> Fut::Output
where
F: FnOnce() -> Fut,
Fut: Future,
Fut::Output: GetSize,
{View on GitHub (pinned to fe841f959e)