{"record":{"id":"e4b1549eebaffa78","repo":"databendlabs/databend","slug":"expect-tuple-type","errorCode":null,"errorMessage":"expect tuple type","messagePattern":"expect tuple type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/storages/common/table_meta/src/meta/column_oriented_segment/segment.rs","lineNumber":213,"sourceCode":"            .unwrap()\n            .as_u_int64()\n            .unwrap()\n            .clone()\n    }\n\n    pub fn col_by_name(&self, name: &[&str]) -> Option<Column> {\n        let (index, field) = self.segment_schema.column_with_name(name[0])?;\n        let column = self.block_metas.get_by_offset(index).to_column();\n        if name.len() == 1 {\n            Some(column)\n        } else {\n            let sub_cols = column.as_tuple().unwrap();\n            match &field.data_type {\n                TableDataType::Tuple {\n                    fields_name,\n                    fields_type,\n                } => Self::col_by_name_inner(&name[1..], sub_cols, fields_name, fields_type),\n                _ => panic!(\"expect tuple type\"),\n            }\n        }\n    }\n\n    fn col_by_name_inner(\n        name: &[&str],\n        cols: &[Column],\n        field_names: &[String],\n        field_types: &[TableDataType],\n    ) -> Option<Column> {\n        let index = field_names.iter().position(|f| f == name[0])?;\n        let column = cols[index].clone();\n        if name.len() == 1 {\n            Some(column)\n        } else {\n            let sub_cols = column.as_tuple().unwrap();\n            match &field_types[index] {\n                TableDataType::Tuple {","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/storages/common/table_meta/src/meta/column_oriented_segment/segment.rs#L195-L231","documentation":"`ColumnOrientedSegment::col_by_name` materializes a segment-level block whose columns are nested tuples (e.g. block-level metadata encoded as tuple columns). It unwraps the outer column as a tuple and expects each selected field's declared type to also be a `TableDataType::Tuple`; when a field is not a tuple it panics with 'expect tuple type', because the lookup by dotted name (`a.b`) can only recurse into tuple sub-columns.","triggerScenarios":"Requesting a column whose first path segment exists but whose declared type is not a Tuple — e.g. calling the helper accessors (`row_count_col`, `stat_col`, `meta_col`, etc., via `check_block_level_meta`) against a segment block whose schema was written by a different format version where the field is a plain scalar instead of a nested tuple struct.","commonSituations":"Reading table metadata segments written by an older/newer Databend version with a changed segment meta schema; corrupted or hand-modified segment files; custom code calling `col_by_name` with a non-tuple top-level field.","solutions":["Verify the segment was written by a compatible table-meta schema version; re-write/compact the segment with the current version.","Check the requested column name path: the first segment must refer to a tuple-typed field in the segment block schema.","Replace the panic with a proper error (e.g. `ErrorCode::UnexpectedColumnCornerCase`) that names the offending field and its actual type."],"exampleFix":"// before\n_ => panic!(\"expect tuple type\"),\n// after\n_ => return Err(ErrorCode::UnexpectedColumnCornerCase(format!(\n    \"expect tuple type for column '{}', got {:?}\", name[0], field.data_type))),","handlingStrategy":"validation","validationCode":"// Verify the requested top-level field is a tuple before lookup\nfn field_is_tuple(schema: &TableSchema, name: &str) -> bool {\n    matches!(schema.field_with_name(name).map(|f| &f.data_type),\n             Ok(TableDataType::Tuple { .. }))\n}","typeGuard":"fn as_tuple(dt: &TableDataType) -> Option<(&Vec<String>, &Vec<TableDataType>)> {\n    if let TableDataType::Tuple { fields_name, fields_type } = dt { Some((fields_name, fields_type)) } else { None }\n}","tryCatchPattern":"let block = std::panic::catch_unwind(AssertUnwindSafe(|| segment.col_by_name(name)))\n    .map_err(|_| format!(\"column '{}' is not a nested tuple in segment\", name))?;","preventionTips":["Keep segment metadata schemas versioned and check the version before reading block-level meta columns.","Validate dotted column paths against the schema before descending.","Never manually edit segment files; regenerate them via compaction.","Prefer returning typed errors over panics in library code reachable from readers."],"tags":["rust","panic","metadata","tuple-column","segment"],"backgroundTag":"type-mismatch","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}