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
- Add `fn accumulate(&mut self, state: &mut ..., arg0: ..., ...) -> ...` inside the same impl block the `#[aggregate]` attribute is applied to.
- Fix the method's spelling to exactly `accumulate`.
- 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
- Always implement `accumulate` first when writing a custom aggregate; add retract/merge/finalize afterwards.
- Keep all aggregate methods in the single impl block annotated with #[aggregate].
- Copy the skeleton from an existing aggregate impl (e.g. src/expr/*/sum.rs style examples).
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
- expect fn
- expect `impl Iterator` in return type
- expected literal
- Expected #[serde_prefix_all(skip)]
- expected string literal
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)