dbt-labs/dbt-core · error · InvalidArgument

Table.select: key must be a string or an array of strings: {

Error message

Table.select: key must be a string or an array of strings: {v} found instead

What it means

Thrown by `Table.select()` when the `key` argument is an iterable but contains an element that is not a string. Each item of the key array must be a column name string; a non-string element (e.g. a number or nested list) triggers this InvalidArgument error. It complements error 391, which covers keys that are not iterable at all.

Source

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

                    Vec::from([single_key.to_string()])
                } else {
                    let iter = match key.try_iter() {
                        Ok(iter) => iter,
                        Err(e) => {
                            return Err(Error::new(
                                ErrorKind::InvalidArgument,
                                format!(
                                    "Table.select: key must be a string or an array of strings: {e}"
                                ),
                            ));
                        }
                    };
                    let mut keys = Vec::new();
                    for v in iter {
                        if let Some(s) = v.as_str() {
                            keys.push(s.to_string());
                        } else {
                            return Err(Error::new(
                                ErrorKind::InvalidArgument,
                                format!(
                                    "Table.select: key must be a string or an array of strings: {v} found instead"
                                ),
                            ));
                        }
                    }
                    keys
                };
                let table = self.select(keys.as_slice());
                Ok(Value::from_object(table))
            }
            "rename" => {
                //     def rename(column_names=None, row_names=None,
                //                slug_columns=False, slug_rows=False,
                //                **kwargs)
                //
                //     column_names: array | dict | None

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Ensure every element of the key list is a string column name
  2. Convert indices to names: `[table.column_names[i] for i in indices]`
  3. Filter or cast the list: `[str(k) for k in keys]` before calling select
  4. Validate the list contents with a type check before the call

Example fix

// before
table.select(['name', 2])
// after
table.select(['name', 'age'])
Defensive patterns

Strategy: type-guard

Validate before calling

def ensure_str_list(keys):
    assert all(isinstance(k, str) for k in keys), f'non-string key: {keys}'
    return keys

Type guard

def is_str_list(v):
    return isinstance(v, (list, tuple)) and all(isinstance(k, str) for k in v)

Try / catch

try:
    result = table.select(keys)
except Exception as e:
    if 'found instead' in str(e):
        result = table.select([str(k) for k in keys])
    else:
        raise

Prevention

When it happens

Trigger: Calling `table.select(['col1', 2])` or any list passed as `key` where at least one element fails `v.as_str()` — mixed-type lists, integer column indices, or nested containers.

Common situations: Dynamically constructed column lists that mix names and indices; deserialized JSON where column selectors were numbers; refactored code passing column positions instead of names.

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/ff2ce95554905706. Report an issue: GitHub.