pola-rs/polars · error

{}

Error message

{}

What it means

accumulate_dataframes_vertical_unchecked stacks DataFrames vertically without checking schema compatibility, but it does check that all frames have the same width. When a subsequent frame's width differs from the accumulated one, it panics with the width_mismatch message. 'Unchecked' means column names/dtypes are not validated — only width.

Solutions

  1. Ensure all input DataFrames have the same number of columns before calling (pad with nulls or drop extra columns)
  2. When reading heterogeneous files, use explicit schema overrides / a unified schema (e.g. hive/partitioned scan schemas) so every fragment yields the same width
  3. Use the checked accumulate_dataframes_vertical (or lazy concat with 'diagonal'/'vertical_relaxed' how) instead of the _unchecked variant
  4. Log/print each df.width() in the iterator to find which frame diverges

Example fix

// before
let df = accumulate_dataframes_vertical_unchecked(frames);
// after
let width = frames.peek().map(|f| f.width());
let frames = frames.map(|f| if f.width() == width { f } else { fix_or_pad(f) });
let df = accumulate_dataframes_vertical_unchecked(frames);
Defensive patterns

Strategy: validation

Validate before calling

let widths: Vec<usize> = frames.iter().map(|f| f.width()).collect();
if !widths.iter().all(|w| *w == widths[0]) {
    panic!("frame widths differ: {:?}", widths);
}

Try / catch

match std::panic::catch_unwind(|| accumulate_dataframes_vertical_unchecked(frames.clone())) {
    Ok(df) => df,
    Err(_) => accumulate_dataframes_vertical(frames), // checked variant
}

Prevention

When it happens

Trigger: Passing an iterator of DataFrames with differing column counts to accumulate_dataframes_vertical_unchecked; called from scan/read/execution paths (finish, finish_reader, execute_chunks, chunk_df_for_writing) when file/fragment schemas disagree.

Common situations: Reading multiple CSV/parquet files with different numbers of columns through one scan; schema drift between partitions; a projection changing width mid-iteration; concatenating frames where a select dropped a column.

Related errors


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

Appendix: source

Thrown at crates/polars-core/src/utils/mod.rs:870

        df1.width(),
        df2.width(),
    )
}

/// This takes ownership of the DataFrame so that drop is called earlier.
/// Does not check if schema is correct
pub fn accumulate_dataframes_vertical_unchecked<I>(dfs: I) -> DataFrame
where
    I: IntoIterator<Item = DataFrame>,
{
    let mut iter = dfs.into_iter();
    let additional = iter.size_hint().0;
    let mut acc_df = iter.next().unwrap();
    acc_df.reserve_chunks(additional);

    for df in iter {
        if acc_df.width() != df.width() {
            panic!("{}", width_mismatch(&acc_df, &df));
        }

        acc_df.vstack_mut_owned_unchecked(df);
    }
    acc_df
}

/// This takes ownership of the DataFrame so that drop is called earlier.
/// # Panics
/// Panics if `dfs` is empty.
pub fn accumulate_dataframes_vertical<I>(dfs: I) -> PolarsResult<DataFrame>
where
    I: IntoIterator<Item = DataFrame>,
{
    let mut iter = dfs.into_iter();
    let additional = iter.size_hint().0;
    let mut acc_df = iter.next().unwrap();
    acc_df.reserve_chunks(additional);

View on GitHub (pinned to fe841f959e)