dbt-labs/dbt-core · error

ColumnsAsTuple::index_of

Error message

ColumnsAsTuple::index_of

What it means

`ColumnsAsTuple::index_of` in dbt-agate is a `todo!()` placeholder in the `TupleRepr` trait implementation, so calling it panics with "ColumnsAsTuple::index_of". The columns-as-tuple view cannot yet locate the position of a value among a table's columns. Any tuple-style `index_of` lookup against the table's column collection panics.

Source

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

    }
}

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 {
    /// Internal representation of the columns sequence is the table representation itself.
    of_table: Arc<TableRepr>,
}

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Avoid `index_of` on the columns tuple view; find the column position by iterating column names/values manually.
  2. Use a representation that implements `index_of` (e.g., row tuples) if applicable.
  3. Implement the method upstream: iterate columns in order and return `Some(i)` for the first column equal to the needle, else `None`.

Example fix

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

Strategy: validation

Validate before calling

// avoid the call; find the column position manually:
let idx = (0..table.num_columns())
    .find(|&i| table.column_value(i) == *needle);

Type guard

fn supports_index_of(repr: &dyn TupleRepr) -> bool {
    (repr as &dyn std::any::Any).downcast_ref::<ColumnsAsTuple>().is_none()
}

Try / catch

// isolate the placeholder if unavoidable:
let idx = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| repr.index_of(&needle)))
    .unwrap_or(None);

Prevention

When it happens

Trigger: Calling `index_of(&value)` on a `ColumnsAsTuple` for any needle value, e.g., asking which column equals a given value.

Common situations: Porting Python agate code that calls `.index(...)` on a table's columns tuple to the Rust dbt-agate port; generic tuple-repr algorithms that fall back to `index_of`.

Related errors


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