pola-rs/polars · error
creating extension types not allowed - try setting the…
Error message
creating extension types not allowed - try setting the environment variable POLARS_ALLOW_EXTENSION
What it means
Polars' Object/extension dtype stores arbitrary Rust values in an Arrow ExtensionArray. Because the on-disk/FFI layout of extension arrays is not guaranteed stable, creating them is gated behind an explicit opt-in: either the POLARS_ALLOW_EXTENSION environment variable is set or the POLARS_ALLOW_EXTENSION feature gate was compiled in. Without it, create_extension panics to prevent users from unknowingly producing data with unsafe/unsupported semantics.
Solutions
- Set the environment variable POLARS_ALLOW_EXTENSION=1 before running the program to opt in to extension type creation
- If you control the build, enable the compile-time POLARS_ALLOW_EXTENSION flag instead of the env var
- Avoid the object/extension dtype entirely and model the data with supported dtypes (struct, list, string)
Example fix
// before
let out = df.group_by(["k"])?.agg([col("obj").agg_list()]); // panics
// after
// in shell / process env:
std::env::set_var("POLARS_ALLOW_EXTENSION", "1");
let out = df.group_by(["k"])?.agg([col("obj").agg_list()]); Defensive patterns
Strategy: validation
Validate before calling
if std::env::var("POLARS_ALLOW_EXTENSION").is_err() {
std::env::set_var("POLARS_ALLOW_EXTENSION", "1"); // or avoid object dtype
} Try / catch
let result = std::panic::catch_unwind(|| build_object_series());
Prevention
- Set POLARS_ALLOW_EXTENSION early in process bootstrap when using the object feature
- Prefer struct dtype over object dtype for new code
- Document the env var requirement in any team/container config
When it happens
Trigger: Any API that builds an ObjectChunked / PolarsExtension, e.g. calling agg_list or finish on a Series/ObjectChunked of a custom Rust type (via #[derive(PolarsObject)] types) while neither the compiled-in POLARS_ALLOW_EXTENSION flag nor the env var is present.
Common situations: Using polars' object dtype feature with custom structs in GroupBy aggregations, or after upgrading polars where the opt-in became mandatory; running in environments (tests, containers) where the env var was never set.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- could not parse table width argument
- invalid value for
- invalid value for POLARS_NDJSON_CHUNK_SIZE
- multiple nested objects not yet supported
- ordering for Object dtype is not supported
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/7428141737b476de.
Report an issue: GitHub.
Appendix: source
Thrown at crates/polars-core/src/chunked_array/object/extension/mod.rs:69
(drop_fn)()
}
}
}
// https://stackoverflow.com/questions/28127165/how-to-convert-struct-to-u8d
// not entirely sure if padding bytes in T are initialized or not.
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
std::slice::from_raw_parts((p as *const T) as *const u8, size_of::<T>())
}
/// Create an extension Array that can be sent to arrow and (once wrapped in [`PolarsExtension`] will
/// also call drop on `T`, when the array is dropped.
pub(crate) fn create_extension<I: Iterator<Item = Option<T>> + TrustedLen, T: Sized + Default>(
iter: I,
) -> PolarsExtension {
let env = "POLARS_ALLOW_EXTENSION";
if !(POLARS_ALLOW_EXTENSION.load() || std::env::var(env).is_ok()) {
panic!("creating extension types not allowed - try setting the environment variable {env}")
}
let t_size = size_of::<T>();
let t_alignment = align_of::<T>();
let n_t_vals = iter.size_hint().1.unwrap();
let mut buf = Vec::with_capacity(n_t_vals * t_size);
let mut validity = BitmapBuilder::with_capacity(n_t_vals);
// when we transmute from &[u8] to T, T must be aligned correctly,
// so we pad with bytes until the alignment matches
let n_padding = (buf.as_ptr() as usize) % t_alignment;
buf.extend(std::iter::repeat_n(0, n_padding));
// transmute T as bytes and copy in buffer
for opt_t in iter.into_iter() {
match opt_t {
Some(t) => {
unsafe {View on GitHub (pinned to fe841f959e)