dbt-labs/dbt-core · error

ColumnsAsTuple::count_occurrences_of

Error message

ColumnsAsTuple::count_occurrences_of

What it means

`ColumnsAsTuple::count_occurrences_of` in dbt-agate is a `todo!()` placeholder in the `TupleRepr` trait implementation, so calling it panics with the message "ColumnsAsTuple::count_occurrences_of". The columns-as-tuple view of a Table does not yet support counting occurrences of a value across its columns. Any code that treats a table's columns like an agate Python tuple and asks how many entries equal a given value will hit this panic.

Source

Thrown at crates/dbt-agate/src/columns.rs:212

    }

    pub fn into_tuple(self) -> Tuple {
        Tuple(Box::new(self))
    }
}

impl TupleRepr for ColumnsAsTuple {
    fn get_item_by_index(&self, idx: isize) -> Option<Value> {
        let column = self.of_table.get_column(idx)?;
        Some(Value::from_object(column))
    }

    fn len(&self) -> usize {
        self.of_table.num_columns()
    }

    fn count_occurrences_of(&self, _needle: &Value) -> usize {
        todo!("ColumnsAsTuple::count_occurrences_of")
    }

    fn index_of(&self, _needle: &Value) -> Option<usize> {
        todo!("ColumnsAsTuple::index_of")
    }

    fn clone_repr(&self) -> Box<dyn TupleRepr> {
        Box::new(ColumnsAsTuple {
            of_table: Arc::clone(&self.of_table),
        })
    }
}

/// Represents an instance of a `MappedSequence` populated by a list of columns.
///
/// https://github.com/wireservice/agate/blob/7023e35b51e8abfe9784fe292a23dd4d7d983c63/agate/table/__init__.py#L181
#[derive(Debug)]
pub struct Columns {

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Avoid calling `count_occurrences_of` on the columns tuple view; iterate the table's rows/values and count manually instead.
  2. Use the row-oriented tuple representation instead of `ColumnsAsTuple` if the operation is available there.
  3. Implement the method upstream: delegate to comparing each column against the needle (per the Python agate semantics) and return the match count.

Example fix

// before (crates/dbt-agate/src/columns.rs)
fn count_occurrences_of(&self, _needle: &Value) -> usize {
    todo!("ColumnsAsTuple::count_occurrences_of")
}
// after
fn count_occurrences_of(&self, needle: &Value) -> usize {
    (0..self.len()).filter(|i| self.get(i).map_or(false, |v| v == needle)).count()
}
Defensive patterns

Strategy: validation

Validate before calling

// avoid the call entirely; count manually:
let count = table.rows()
    .filter(|row| row.values().iter().any(|v| v == &needle))
    .count();

Type guard

fn supports_tuple_repr_op(repr: &dyn TupleRepr) -> bool {
    // ColumnsAsTuple does not implement count_occurrences_of/index_of
    (repr as &dyn std::any::Any).downcast_ref::<ColumnsAsTuple>().is_none()
}

Try / catch

// isolate the placeholder if a trait object must be used:
let n = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| repr.count_occurrences_of(&needle)))
    .unwrap_or(0);

Prevention

When it happens

Trigger: Calling `count_occurrences_of(&value)` on a `ColumnsAsTuple` (e.g., a table's `.columns` view used as a tuple) for any needle value.

Common situations: Porting agate Python table operations (e.g., `values.count(...)`) to the Rust dbt-agate port; code doing membership/multiplicity checks on a table's column collection.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/cd17abcab391c0c1. Report an issue: GitHub.