dbt-labs/dbt-core · error

Table.distinct: error creating grouper

Error message

Table.distinct: error creating grouper: {e}

What it means

distinct builds a grouper over the specified (or all) columns to identify unique rows. If grouper construction fails — unknown column name or unsupported column type — the error is wrapped as 'Table.distinct: error creating grouper'.

Solutions

  1. Verify every name in the subset list exists in the table's column_names.
  2. Call distinct with no subset to dedupe on all columns, or restrict the subset to primitive-typed columns.
  3. Read the wrapped inner error for the precise cause (missing column vs unsupported dtype) and fix the input accordingly.

Example fix

// before
table.distinct(Some(vec!["user_id", "evnt_date"]), None)? // typo
// after
table.distinct(Some(vec!["user_id", "event_date"]), None)?
Defensive patterns

Strategy: validation

Validate before calling

let names = table.column_names();
if let Some(sub) = &subset {
    for c in sub {
        if !names.contains(c) { return Err(format!("column '{c}' not found")); }
    }
}

Try / catch

match table.distinct(subset, key_type) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("error creating grouper") => {
        eprintln!("{e}");
        // fix subset names/types and retry, or dedupe on all columns
        table.distinct(None, None)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling table.distinct with a subset argument naming a column that does not exist, or distinct over columns with types the grouper cannot hash (e.g. nested types).

Common situations: Typo in the subset column list; upstream schema drift renamed a column; deduplicating on struct/list columns unsupported by the grouper.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at crates/dbt-agate/src/table.rs:948

    fn distinct(&self, key: Option<Vec<String>>) -> Result<AgateTable, Error> {
        let column_names = match key {
            Some(keys) => self
                .column_names()
                .iter()
                .filter_map(|key| {
                    if keys.contains(key) {
                        Some(key.clone())
                    } else {
                        None
                    }
                })
                .collect(),
            None => self.column_names(),
        };
        // TODO: cast the values in `column` according to `key_type`, create a new
        // table with the casted column, and use that table to create the grouper
        let grouper = self.grouper(&column_names).map_err(|e| {
            Error::new(
                ErrorKind::InvalidOperation,
                format!("Table.distinct: error creating grouper: {e}"),
            )
        })?;

        // Builds a selection vector with the first `row_idx` of every group.
        // A "group" is the set of rows that are identical, so whenever the
        // grouper emits a `group_id` we've already seen, we know we shouldn't
        // emit that `row_idx` because it's not the index of a distinct row.
        let mut seen_groups = HashSet::new();
        let indices: Vec<u64> = grouper
            .iter()
            .enumerate()
            .filter_map(|(row_idx, group_id)| {
                if seen_groups.insert(group_id) {
                    Some(row_idx as u64)
                } else {
                    None

View on GitHub (pinned to 0267ce9170)