quickwit-oss/quickwit · error · proc-macro compile error

`serde_multikey` was applied to a tuple-struct or an empty s

Error message

`serde_multikey` was applied to a tuple-struct or an empty struct

What it means

generate_proxy_struct builds a proxy struct mirroring the target's fields, which requires named fields (Fields::Named). Tuple structs, unit structs, and structs with unnamed fields cannot be mirrored, so the macro fails compilation with this message.

Source

Thrown at quickwit/quickwit-macros/src/lib.rs:157

    let proxy_ident = Ident::new(&format!("__MultiKey{}", input.ident), input.ident.span());

    input.ident = proxy_ident.clone();
    input.vis = Visibility::Inherited;
    // TODO wait for https://github.com/juhaku/utoipa/issues/704 to re-enable
    // input.attrs.append(&mut Attribute::parse_outer
    // .parse_str(&"#[doc(hidden)]")
    // .unwrap());

    let (ser, de) = get_ser_de(&input.attrs)?;

    let mut pass_through = Vec::<Ident>::new();
    let mut final_fields = Punctuated::<Field, Token![,]>::new();
    let mut try_from_conv = Vec::<TokenStream2>::new();
    let mut into_pre_conv = Vec::<TokenStream2>::new();
    let mut into_in_conv = Vec::<TokenStream2>::new();

    let Fields::Named(FieldsNamed { brace_token, named }) = input.fields else {
        return Err(Error::new(
            Span::call_site(),
            "`serde_multikey` was applied to a tuple-struct or an empty struct",
        ));
    };
    for pair in named.into_pairs() {
        let (mut field, ponct) = pair.into_tuple();
        // we are in a "normal" struct, not a tuple-struct, unwrap is fine.
        let field_name = field.ident.clone().unwrap();

        let (field_config, attrs) = parse_attributes(field.attrs, &field_name)?;
        field.attrs = attrs;

        if let Some(field_config) = field_config {
            let value = Ident::new("value", Span::call_site());
            for field in &field_config.proxy_fields {
                final_fields.push(field.clone());
            }
            match (ser, field_config.get_into(&value)) {

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Convert the struct to use named fields, e.g. `struct Wrapper { value: String }`.
  2. Remove the #[serde_multikey] attribute if multi-key behavior is not actually needed.

Example fix

// before
#[serde_multikey(fields(v))]
struct Wrapper(String);
// after
#[derive(Serialize, Deserialize)]
#[serde_multikey(fields(v))]
struct Wrapper { v: String }
Defensive patterns

Strategy: validation

Validate before calling

// serde_multikey requires named fields; verify struct shape:
// struct Good { key: String }        // OK
// struct Bad(String);                // NOT supported
// struct Unit;                       // NOT supported

Prevention

When it happens

Trigger: Applying #[serde_multikey(...)] to a tuple struct like `struct Wrapper(String);`, a unit struct `struct Unit;`, or any struct without named fields.

Common situations: Trying to make a newtype wrapper multi-key-capable; refactoring a named struct into a tuple struct while keeping the attribute.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/4b45e20d8fabad60. Report an issue: GitHub.