risingwavelabs/risingwave · critical

expect accumulate function

Error message

expect accumulate function

What it means

Parsing an `#[aggregate]` `impl` block requires an `accumulate` method — it is the mandatory core of the aggregate state machine (retract/merge/finalize etc. are optional). `AggregateImpl::parse` uses `.expect("expect accumulate function")` and panics during macro expansion if no method named `accumulate` exists in the impl.

Solutions

  1. Add `fn accumulate(&mut self, state: &mut ..., arg0: ..., ...) -> ...` inside the same impl block the `#[aggregate]` attribute is applied to.
  2. Fix the method's spelling to exactly `accumulate`.
  3. Ensure all aggregate methods (accumulate plus any retract/merge/finalize) live in the single `impl` block annotated with `#[aggregate]`.

Example fix

// before - no accumulate method
#[aggregate]
impl SumState {
    fn create_state() -> Self { Self { sum: 0 } }
}

// after
#[aggregate]
impl SumState {
    fn create_state() -> Self { Self { sum: 0 } }
    fn accumulate(&mut self, v: Option<i64>) { self.sum += v.unwrap_or(0); }
}
Defensive patterns

Strategy: validation

Validate before calling

// Structurally: an #[aggregate] impl block must contain `fn accumulate`
fn has_accumulate(impl_src: &str) -> bool {
    impl_src.contains("fn accumulate(")
}
assert!(has_accumulate("impl S { fn accumulate(&mut self, v: i64) {} }"));

Try / catch

// Compile-time panic; guard with a trybuild test:
// #[test] fn aggregate_requires_accumulate() {
//     trybuild::TestCases::new().compile_fail("tests/ui/aggregate_without_accumulate.rs");
// }

Prevention

When it happens

Trigger: Writing `#[aggregate]` on an `impl MyState { fn retract(...) ... }` block that lacks `fn accumulate(...)`; misspelling it (`accmulate`, `acc`) or defining it as an associated function of another impl block.

Common situations: New contributor scaffolding a custom aggregate from an example that only showed optional methods; renaming `accumulate` during refactors; splitting methods across multiple impl blocks so the macro's single-item-impl scan misses it.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at src/expr/macro/src/parse.rs:157

impl Parse for AggregateImpl {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let itemimpl: syn::ItemImpl = input.parse()?;
        let parse_function = |name: &str| {
            itemimpl.items.iter().find_map(|item| match item {
                syn::ImplItem::Fn(syn::ImplItemFn { sig, .. }) if sig.ident == name => {
                    Some(UserFunctionAttr::from(sig))
                }
                _ => None,
            })
        };
        let self_path = itemimpl.self_ty.to_token_stream().to_string();
        let struct_name = match self_path.split_once('<') {
            Some((path, _)) => path.trim().into(), // remove generic parameters
            None => self_path,
        };
        Ok(AggregateImpl {
            struct_name,
            accumulate: parse_function("accumulate").expect("expect accumulate function"),
            retract: parse_function("retract"),
            merge: parse_function("merge"),
            finalize: parse_function("finalize"),
            create_state: parse_function("create_state"),
            encode_state: parse_function("encode_state"),
            decode_state: parse_function("decode_state"),
        })
    }
}

impl Parse for AggregateFnOrImpl {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        // consume attributes
        let _ = input.call(syn::Attribute::parse_outer)?;
        if input.peek(Token![impl]) {
            Ok(AggregateFnOrImpl::Impl(input.parse()?))
        } else {
            Ok(AggregateFnOrImpl::Fn(input.parse()?))

View on GitHub (pinned to 6469eb736d)