influxdata/influxdb · error

num_row_groups_in_parallel should be above zero

Error message

num_row_groups_in_parallel should be above zero

What it means

ParquetStorage::with_parallel_write_settings wraps its two usize arguments into NonZeroUsize via NonZeroUsize::new(..).expect("num_row_groups_in_parallel should be above zero") (and a sibling expect for num_columns_in_parallel). Passing 0 for either argument makes NonZeroUsize::new return None and panics immediately; the # Panics doc section states this contract. It is a fail-fast config-validation panic at builder time, before any IO happens.

Source

Thrown at core/parquet_file/src/storage.rs:247

            parquet_write_parallelization_settings: Default::default(),
        }
    }

    /// Provide settings for parallelized writes. Settings determine the
    /// amount of parallelization per row group and per column.
    ///
    /// # Panics
    ///
    /// This will panic if an invalid usize (not > 0) is used.
    pub fn with_parallel_write_settings(
        self,
        num_row_group_writers: usize,
        num_column_writers_across_row_groups: usize,
    ) -> Self {
        Self {
            parquet_write_parallelization_settings: ParallelParquetWriterOptions::new(
                NonZeroUsize::new(num_row_group_writers)
                    .expect("num_row_groups_in_parallel should be above zero"),
                NonZeroUsize::new(num_column_writers_across_row_groups)
                    .expect("num_columns_in_parallel should be above zero"),
            ),
            ..self
        }
    }

    /// Get underlying object store.
    pub fn object_store(&self) -> &Arc<DynObjectStore> {
        &self.object_store
    }

    /// Get ID.
    pub fn id(&self) -> StorageId {
        self.id
    }

    /// Fake DataFusion context for testing that contains this store

View on GitHub (pinned to d28e26e048)

Solutions

  1. Pass a value >= 1 for both arguments; if deriving from a formula, clamp with .max(1).
  2. Parse config as NonZeroUsize (or validate > 0 and reject the config at load time) so 0 never reaches the builder.
  3. Round instead of truncate when converting fractional parallelism to usize.
  4. Document/enforce a minimum in your settings layer (e.g. num_row_groups: NonZeroUsize in the config struct).

Example fix

// before
let storage = storage.with_parallel_write_settings(0, num_columns); // panics

// after
let storage = storage.with_parallel_write_settings(num_row_groups.max(1), num_columns.max(1));
Defensive patterns

Strategy: validation

Validate before calling

// validate config before building the storage
let num_row_groups = config.num_row_group_writers; // from CLI/env/file
if num_row_groups == 0 || config.num_column_writers_across_row_groups == 0 {
    return Err("parallel write settings must be >= 1".into());
}
let storage = storage.with_parallel_write_settings(num_row_groups, config.num_column_writers_across_row_groups);

Type guard

// carry NonZeroUsize through your config so 0 is unrepresentable
fn parse_parallelism(raw: &str) -> Result<NonZeroUsize, String> {
    raw.parse::<usize>()
        .ok()
        .and_then(NonZeroUsize::new)
        .ok_or_else(|| format!("'{raw}' must be a positive integer"))
}

Prevention

When it happens

Trigger: Calling with_parallel_write_settings(0, n) or (n, 0); typical sources are CLI/env config parsed straight into usize where unset maps to 0, or computed parallelism like f64 rounding/truncation yielding 0 (e.g. cores*0.25 with 0-1 cores).

Common situations: Config plumbing that defaults parallelism to 0 when a knob is missing; formulas deriving row-group writer counts from table width (n_columns * factor) that floor to 0 for narrow tables; deployments on tiny containers reporting 1 CPU with a fractional multiplier.

Related errors


AI-assisted analysis of influxdata/influxdb@d28e26e048 (2026-08-16). Data as JSON: /api/errors/696a9cd5329237b1. Report an issue: GitHub.