risingwavelabs/risingwave · error

invalid struct type

Error message

invalid struct type

What it means

The `data_type` helper in src/expr/macro/src/gen.rs converts a type string (from function signatures like `struct<a int,b varchar>`) into a `DataType` TokenStream. Strings starting with `struct<` are parsed as a StructType via `DataType::Struct(#ty.parse().expect("invalid struct type"))`; if the text after `struct<` is not a valid serialized struct type, the expect panics during macro expansion.

Source

Thrown at src/expr/macro/src/gen.rs:1471

        "anyarray" => quote! { SigDataType::AnyArray },
        "anymap" => quote! { SigDataType::AnyMap },
        "vector" => quote! { SigDataType::Vector },
        "struct" => quote! { SigDataType::AnyStruct },
        _ if ty.starts_with("struct") && ty.contains("any") => quote! { SigDataType::AnyStruct },
        _ => {
            let datatype = data_type(ty);
            quote! { SigDataType::Exact(#datatype) }
        }
    }
}

fn data_type(ty: &str) -> TokenStream2 {
    if let Some(ty) = ty.strip_suffix("[]") {
        let inner_type = data_type(ty);
        return quote! { DataType::list(#inner_type) };
    }
    if ty.starts_with("struct<") {
        return quote! { DataType::Struct(#ty.parse().expect("invalid struct type")) };
    }
    let variant = format_ident!("{}", types::data_type(ty));
    // TODO: enable the check
    // assert!(
    //     !matches!(ty, "any" | "anyarray" | "anymap" | "struct"),
    //     "{ty}, {variant}"
    // );

    quote! { DataType::#variant }
}

/// Extract multiple output types.
///
/// ```ignore
/// output_types("int4") -> ["int4"]
/// output_types("struct<key varchar, value jsonb>") -> ["varchar", "jsonb"]
/// ```
fn output_types(ty: &str) -> Vec<&str> {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Fix the `struct<...>` string so it matches the StructType parse format, e.g. `struct<a int,b varchar>` with matching field-name/type pairs and a closing `>`.
  2. Verify against existing struct-typed function declarations in the repo and copy a known-good example.
  3. If a custom/nested shape is needed, build the type with `type_infer` returning a computed `DataType` instead of the inline struct string.

Example fix

// before - missing type after field name breaks the parse
#[function("f(struct<a int,b>)")]

// after
#[function("f(struct<a int,b varchar>)")]
Defensive patterns

Strategy: validation

Validate before calling

// Validate struct type strings before putting them in a signature
fn valid_struct_type(s: &str) -> bool {
    s.starts_with("struct<")
        && s.ends_with('>')
        && s[7..s.len() - 1].split(',').all(|f| {
            let mut it = f.trim().split_whitespace();
            it.next().map(|n| !n.is_empty()).unwrap_or(false).then(|| ()).and_then(|_| it.next()).is_some()
        })
}
assert!(valid_struct_type("struct<a int,b varchar>"));

Prevention

When it happens

Trigger: Declaring a function signature whose argument or return type is `struct<...>` with malformed inner syntax — missing closing `>`, bad field specifiers, or a struct literal that the StructType parser cannot deserialize.

Common situations: Hand-writing struct types in `#[function("f(struct<a int>)")]-style signatures; typos in the field/type syntax; copying struct type strings between formats that use different serialization.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/c70805cbfe2fc0ff. Report an issue: GitHub.