cube-js/cube · error

unexpected value {:?} for type {:?}

Error message

unexpected value {:?} for type {:?}

What it means

append_value panics when a TableValue handed to a typed column builder is of a different variant than the column's declared type (other than null). The macro-generated match only accepts values matching the column enum; anything else is a programming/data bug.

Source

Thrown at rust/cubestore/cubestore/src/table/data.rs:246

            $v.as_str()
        }};
        (Bytes, $v: expr) => {{
            $v.as_slice()
        }};
        ($tv_enum: tt, $v: expr) => {{
            *$v
        }};
    }
    macro_rules! append {
        ($type: tt, $builder: tt, $tv_enum: tt $(, $arg:tt)*) => {{
            let b = b.as_any_mut().downcast_mut::<$builder>().unwrap();
            if is_null {
                b.append_null();
                return;
            }
            let v = match v {
                TableValue::$tv_enum(v) => convert_value!($tv_enum, v),
                other => panic!("unexpected value {:?} for type {:?}", other, c),
            };
            b.append_value(v);
        }};
    }
    match_column_type!(c, append)
}

pub fn rows_to_columns(cols: &[Column], rows: &[Row]) -> Vec<ArrayRef> {
    let mut builders = create_array_builders(&cols);
    for r in rows {
        append_row(&mut builders, &cols, r);
    }
    builders.into_iter().map(|mut b| b.finish()).collect_vec()
}

pub fn to_stream(r: RecordBatch) -> SendableRecordBatchStream {
    let schema = r.schema();
    // TaskContext::default is OK here because it's a plain memory exec.

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Coerce values to the declared column type before appending (parse strings, cast numbers)
  2. Fix the ingestion/import path so each column receives values of its declared type
  3. Verify pre-aggregation rollup column types match the aggregate function's result type
  4. Re-check source data for malformed rows breaking type inference

Example fix

// before
builder.append_value(TableValue::String(s)); // column is Int
// after
builder.append_value(TableValue::Int(s.parse::<i64>().expect("invalid int")));
Defensive patterns

Strategy: validation

Validate before calling

fn coerce_for_column(v: TableValue, col: ColumnType) -> Result<TableValue, String> {
    match (&v, col) {
        (TableValue::String(s), ColumnType::Int) => s.parse::<i64>().map(TableValue::Int).map_err(|e| e.to_string()),
        (TableValue::Int(_), ColumnType::Int) | (TableValue::String(_), ColumnType::String) => Ok(v),
        (other, c) => Err(format!("value {:?} does not match column type {:?}", other, c)),
    }
}

Type guard

fn matches_column(v: &TableValue, col: &ColumnType) -> bool {
    matches!((v, col), (TableValue::Int(_), ColumnType::Int) | (TableValue::String(_), ColumnType::String))
}

Prevention

When it happens

Trigger: Writing a result/import row where a value's TableValue variant doesn't match the column type — e.g. append_csv_value importing a string into an Int column, or write_group_result_row emitting an aggregation result of the wrong type.

Common situations: CSV import with inconsistent column values; custom ingestion code pushing uncoerced values; aggregation producing a type different from the target column (e.g. Sum of Decimal into Int column).

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/feb4af65044b92e4. Report an issue: GitHub.