{"record":{"id":"b103c6c420b34127","repo":"risingwavelabs/risingwave","slug":"expects-a-struct-array-ref","errorCode":null,"errorMessage":"expects a struct array ref","messagePattern":"expects a struct array ref","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/scalar/field.rs","lineNumber":45,"sourceCode":"pub struct FieldExpression<E> {\n    return_type: DataType,\n    input: E,\n    index: usize,\n}\n\nimpl<E: ExpressionInfo> ExpressionInfo for FieldExpression<E> {\n    fn return_type(&self) -> DataType {\n        self.return_type.clone()\n    }\n}\n\nmacro_rules! eval_field {\n    ($mode:ident, $this:expr, $input:expr) => {{\n        let array = risingwave_expr::forward!($mode, $this.input, eval($input))?;\n        if let ArrayImpl::Struct(struct_array) = array.as_ref() {\n            Ok(struct_array.field_at($this.index).clone())\n        } else {\n            Err(anyhow!(\"expects a struct array ref\").into())\n        }\n    }};\n}\n\nmacro_rules! eval_row_field {\n    ($mode:ident, $this:expr, $input:expr) => {{\n        let struct_datum = risingwave_expr::forward!($mode, $this.input, eval_row($input))?;\n        struct_datum\n            .map(|s| match s {\n                ScalarImpl::Struct(v) => Ok(v.fields()[$this.index].clone()),\n                _ => Err(anyhow!(\"expects a struct array ref\").into()),\n            })\n            .transpose()\n            .map(|x| x.flatten())\n    }};\n}\n\nimpl<E: SyncExpression> SyncExpression for FieldExpression<E> {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/scalar/field.rs#L27-L63","documentation":"The field-access expression's array evaluation expects its evaluated input to be a StructArray; anything else (e.g. a ListArray or other variant) triggers this anyhow-based error. It indicates the input expression's type didn't match the struct-field-access requirement.","triggerScenarios":"Evaluating a field access expression whose input array is not ArrayImpl::Struct — e.g. accessing `.field` on a non-struct column, or after a cast/reorganization changed the input to a list or primitive array.","commonSituations":"Querying a nested field of a column that is actually a list/array rather than a struct; schema drift where a struct column became a different type; incorrect expr construction in custom planners.","solutions":["Ensure the input expression's return type is a STRUCT before applying field access.","Unnest lists first (e.g. FLATTEN/unnest) before accessing struct fields inside them.","Verify the source schema: the accessed column must genuinely be a struct type."],"exampleFix":"// before\nfield_access(input_list_expr, index) // input is ListArray\n// after\nfield_access(unnest_or_cast_to_struct(input_list_expr), index)","handlingStrategy":"validation","validationCode":"if !matches!(input.return_type(), DataType::Struct(_)) {\n    return Err(\"field access requires a struct input\".into());\n}","typeGuard":"fn is_struct_input(e: &BoxedExpression) -> bool { matches!(e.return_type(), DataType::Struct(_)) }","tryCatchPattern":null,"preventionTips":["Check the column type in the catalog before writing nested field access.","Unnest lists before accessing struct fields within them.","Guard generic expression builders to only create field access on struct-typed inputs."],"tags":["expression","struct","type-mismatch"],"backgroundTag":"incompatible-source-type","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}