influxdata/influxdb · error · syn::Error

` ` must have exactly one type parameter

Error message

`{name}` must have exactly one type parameter

What it means

A compile-time error from the catalog record field-type checker. Whitelisted container types (those in `CONTAINERS`) must carry exactly one type argument, and that argument must itself be a type (not a lifetime or const). Zero, multiple, or non-type arguments make the persisted shape ambiguous, so `check_path` rejects them before recursing into the single inner type.

Solutions

  1. Write the container with exactly one type argument: `Option<T>` or `Vec<T>`.
  2. If extra parameters (allocator, capacity) are needed, drop them or encode the fixed layout in a dedicated wire type in `records::types`.

Example fix

// before
#[catalog_record(shape = 0x1)]
struct Foo { items: Vec<u64, CustomAlloc> }

// after
#[catalog_record(shape = 0x1)]
struct Foo { items: Vec<u64> }
Defensive patterns

Strategy: validation

Validate before calling

// Containers must have exactly one type argument:
// OK: Vec<u64>, Option<String>
// NOT OK: Vec<u64, Alloc>, Option<>

Prevention

When it happens

Trigger: Declaring a field like `field: Option<>` (empty), `field: Vec<u64, Alloc>` (two arguments), or `field: Option<'a T>`-style arguments where the inner-type filter yields a count that isn't exactly 1. Raised in `check_path` when `inner.len() != 1`.

Common situations: A developer writes a container with a custom allocator/capacity parameter, or leaves an incomplete generic argument while editing.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/e1f3baa57a8b9981. Report an issue: GitHub.

Appendix: source

Thrown at influxdb3_catalog_macros/src/types.rs:86

                    format!(
                        "`{name}` is generic. Only {} may take type parameters in a catalog \
                         record, and any other generic must be parameterised solely by const \
                         literals (e.g. `Reserved<16>`); a generic body has no single persisted \
                         shape.",
                        CONTAINERS.join(" and ")
                    ),
                ));
            }
            let inner: Vec<&Type> = args
                .args
                .iter()
                .filter_map(|arg| match arg {
                    GenericArgument::Type(t) => Some(t),
                    _ => None,
                })
                .collect();
            if inner.len() != args.args.len() || inner.len() != 1 {
                return Err(syn::Error::new(
                    ty.span(),
                    format!("`{name}` must have exactly one type parameter"),
                ));
            }
            check(inner[0])
        }
        PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => Err(unsupported(ty)),
    }
}

/// Whether a generic argument is a const *literal*, the only generic argument
/// permitted outside `Option`/`Vec`. See the call site for why.
fn is_const_literal(arg: &GenericArgument) -> bool {
    matches!(
        arg,
        GenericArgument::Const(syn::Expr::Lit(syn::ExprLit {
            lit: syn::Lit::Int(_),
            ..

View on GitHub (pinned to 06200ef96b)