nushell/nushell · error

Already checked that is a series

Error message

Already checked that is a series

What it means

Panic in NuDataFrame::computed_binary_op (operations.rs): in the (true, true) arm after matching (self.is_series(), rhs.is_series()), the lhs is converted with as_series(lhs_span).expect('Already checked that is a series'). Since the match arm only runs when both frames have width 1, as_series cannot take its error branch and first() cannot be None — the expect documents the match/lookup agreement and is effectively unreachable.

Source

Thrown at crates/nu_plugin_polars/src/dataframe/values/nu_dataframe/operations.rs:37

impl NuDataFrame {
    pub fn compute_with_value(
        &self,
        plugin: &PolarsPlugin,
        lhs_span: Span,
        operator: Operator,
        op_span: Span,
        right: &Value,
    ) -> Result<NuDataFrame, ShellError> {
        let rhs_span = right.span();
        match right {
            Value::Custom { .. } => {
                let rhs = NuDataFrame::try_from_value_coerce(plugin, right, rhs_span)?;

                match (self.is_series(), rhs.is_series()) {
                    (true, true) => {
                        let lhs = &self
                            .as_series(lhs_span)
                            .expect("Already checked that is a series");
                        let rhs = &rhs
                            .as_series(rhs_span)
                            .expect("Already checked that is a series");

                        if lhs.dtype() != rhs.dtype() {
                            return Err(ShellError::IncompatibleParameters {
                                left_message: format!("datatype {}", lhs.dtype()),
                                left_span: lhs_span,
                                right_message: format!("datatype {}", lhs.dtype()),
                                right_span: rhs_span,
                            });
                        }

                        if lhs.len() != rhs.len() {
                            return Err(ShellError::IncompatibleParameters {
                                left_message: format!("len {}", lhs.len()),
                                left_span: lhs_span,
                                right_message: format!("len {}", rhs.len()),

View on GitHub (pinned to 8e03210652)

Solutions

  1. Keep is_series() and as_series()'s width check derived from the same predicate when refactoring
  2. Avoid sharing/mutating NuDataFrame values across threads during operations
  3. Consider replacing the expects in the (true, true) arm with error returns to future-proof

Example fix

// before
let lhs = &self.as_series(lhs_span).expect("Already checked that is a series");

// after: reuse the already-checked width directly
let lhs = self.df.get_columns()[0].as_materialized_series();
Defensive patterns

Strategy: validation

Validate before calling

// ensure both operands are single-column before the operation
if !(lhs.is_series() && rhs.is_series()) {
    return Err(ShellError::IncompatibleParametersSingle { msg: "operands must be single-column dataframes".into(), span: lhs_span });
}

Type guard

fn both_series(l: &NuDataFrame, r: &NuDataFrame) -> bool {
    l.is_series() && r.is_series()
}

Prevention

When it happens

Trigger: Divergence between the is_series() predicate and as_series()'s internal check (e.g. someone changes one without the other), or concurrent mutation of either dataframe between the match and the conversion.

Common situations: Only relevant to nu_plugin_polars maintainers/refactors; users performing arithmetic between single-column dataframes get real ShellErrors (IncompatibleParameters, etc.) long before this can matter.

Related errors


AI-assisted analysis of nushell/nushell@8e03210652 (2026-08-17). Data as JSON: /api/errors/40bfe9b9913f637e. Report an issue: GitHub.