pola-rs/polars · error

activate 'decompress' feature

Error message

activate 'decompress' feature

What it means

try_new for a compressed reader panics when the input is zstd-compressed (or any compression other than the always-supported ones) and the 'decompress' feature is not enabled. The build lacks the decompression backends, so it cannot handle this input and deliberately aborts.

Solutions

  1. Enable the decompress feature: polars = { features = ["decompress"], ... }.
  2. Pre-decompress the file yourself (e.g. zstd -d) and feed plain bytes.
  3. If reading through higher-level APIs, check which feature they need (csv/json/ipc with 'decompress').

Example fix

// before
polars = { version = "0.46", features = ["csv"] }
// after
polars = { version = "0.46", features = ["csv", "decompress"] }
Defensive patterns

Strategy: validation

Validate before calling

fn needs_decompress(path: &str) -> bool {
    path.ends_with(".zst") || path.ends_with(".zstd")
}
assert!(!needs_decompress(path), "enable polars feature 'decompress' for zstd inputs");

Try / catch

// It's a panic; gate at startup/feature time, not at call time
#[cfg(not(feature = "polars/decompress"))]
compile_error!("this build reads compressed files; enable polars 'decompress' feature");

Prevention

When it happens

Trigger: Constructing CompressedReader::try_new from a buffer whose detected compression is ZSTD (or another decompress-gated codec) on a build without feature = "decompress".

Common situations: Reading .zst-compressed CSV/IPC files with default polars features; minimal Cargo feature sets that omit decompress; upgrading and forgetting to re-add the feature.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/157c05d941fd9db6. Report an issue: GitHub.

Appendix: source

Thrown at crates/polars-io/src/utils/compression.rs:108

    pub fn try_new(slice: Buffer<u8>) -> PolarsResult<Self> {
        let algo = SupportedCompression::check(&slice);

        Ok(match algo {
            None => CompressedReader::Uncompressed { slice, offset: 0 },
            #[cfg(feature = "decompress")]
            Some(SupportedCompression::GZIP) => {
                CompressedReader::Gzip(flate2::bufread::MultiGzDecoder::new(Cursor::new(slice)))
            },
            #[cfg(feature = "decompress")]
            Some(SupportedCompression::ZLIB) => {
                CompressedReader::Zlib(flate2::bufread::ZlibDecoder::new(Cursor::new(slice)))
            },
            #[cfg(feature = "decompress")]
            Some(SupportedCompression::ZSTD) => {
                CompressedReader::Zstd(zstd::Decoder::with_buffer(Cursor::new(slice))?)
            },
            #[cfg(not(feature = "decompress"))]
            _ => panic!("activate 'decompress' feature"),
        })
    }

    pub fn is_compressed(&self) -> bool {
        !matches!(&self, CompressedReader::Uncompressed { .. })
    }

    pub const fn initial_read_size() -> usize {
        // We don't want to read too much at the beginning to keep decompression to a minimum if for
        // example only the schema is needed or a slice op is used. Keep in sync with
        // `ideal_read_size` so that `initial_read_size * N * 4 == ideal_read_size`.
        32 * 1024
    }

    pub const fn ideal_read_size() -> usize {
        // Somewhat conservative guess for L2 size, which performs the best on most machines and is
        // nearly always core exclusive. The loss of going larger and accidentally hitting L3 is not
        // recouped by amortizing the block processing cost even further.

View on GitHub (pinned to fe841f959e)