databendlabs/databend · error
DataType::Map should contain a struct field child
Error message
DataType::Map should contain a struct field child
What it means
This is an internal invariant panic in the Delta Lake storage's Arrow 5.6 type conversion layer. When converting an Arrow Map type to Databend's DataType, the converter expects the Map's single field child to be a Struct containing exactly the key and value fields; any Arrow schema that violates this (e.g. a Map whose child is not a Struct) triggers an immediate panic via unreachable!() instead of a recoverable error.
Solutions
- Inspect the offending Arrow schema and confirm the Map field's child is a Struct with key and value entries
- Fix the upstream writer or regenerate the Delta table so Map columns use the standard struct(key, value) child layout
- Replace the panic with a proper Err(Arrow56ConversionError::InvalidDataType(...)) so bad schemas surface as a readable error instead of aborting the query
- Pin/align the arrow crate versions used to write and read the data
Example fix
// before
} else {
panic!("DataType::Map should contain a struct field child");
}
// after
} else {
return Err(Arrow56ConversionError::InvalidDataType(format!(
"DataType::Map should contain a struct field child, got {:?}",
field.data_type()
)));
} Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_arrow_map(field: &ArrowField) -> bool {
matches!(field.data_type(), ArrowDataType::Struct(children) if children.len() >= 2)
}
if !is_valid_arrow_map(&field) {
return Err(Arrow56ConversionError::InvalidDataType(
"Map field child is not a struct".into(),
));
} Type guard
fn is_struct_type(dt: &ArrowDataType) -> bool {
matches!(dt, ArrowDataType::Struct(_))
} Try / catch
// Panics cannot be caught idiomatically in Rust; prefer validating before conversion.
let result = std::panic::catch_unwind(|| DataType::try_from_value(&field));
match result {
Ok(Ok(dt)) => use_datatype(dt),
Ok(Err(e)) => report_conversion_error(e),
Err(_) => report_schema_bug(),
} Prevention
- Validate Arrow schemas coming from external Delta/Parquet sources before conversion
- Keep arrow crate versions aligned between writer and reader paths
- Prefer returning Err over panic! for malformed external input
When it happens
Trigger: Calling DataType::try_from_value on an Arrow Field whose data_type is ArrowDataType::Map when field.data_type() does not match ArrowDataType::Struct(_) — e.g. reading a Delta table whose Parquet/Arrow schema encodes Map with a malformed or non-struct child field.
Common situations: Ingesting a Delta table written by another engine or library version that serializes Map columns differently; corrupted or hand-crafted Parquet metadata; a version mismatch between the arrow crate that wrote the data and the arrow56 shim used by the converter.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- invalid map type
- internal error: entered unreachable code
- Error parsing first message
- Error parsing dictionary
- Error reading dictionary
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/2145b99d8262411c.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/storages/delta/src/arrow56_conversion.rs:310
.into()),
ArrowDataType::LargeListView(field) => Ok(ArrayType::new(
(*field).data_type().try_into_value()?,
(*field).is_nullable(),
)
.into()),
ArrowDataType::FixedSizeList(field, _) => Ok(ArrayType::new(
(*field).data_type().try_into_value()?,
(*field).is_nullable(),
)
.into()),
ArrowDataType::Map(field, _) => {
if let ArrowDataType::Struct(struct_fields) = field.data_type() {
let key_type = DataType::try_from_value(struct_fields[0].data_type())?;
let value_type = DataType::try_from_value(struct_fields[1].data_type())?;
let value_type_nullable = struct_fields[1].is_nullable();
Ok(MapType::new(key_type, value_type, value_type_nullable).into())
} else {
panic!("DataType::Map should contain a struct field child");
}
}
// Dictionary types are just an optimized in-memory representation of an array.
// Schema-wise, they are the same as the value type.
ArrowDataType::Dictionary(_, value_type) => Ok(value_type.as_ref().try_into_value()?),
s => Err(Arrow56ConversionError::InvalidDataType(format!(
"Invalid data type for Delta Lake: {s}"
))),
}
}
}
View on GitHub (pinned to 288d84d76e)