risingwavelabs/risingwave · error

type inference for this function should be specially handled

Error message

type inference for this function should be specially handled in frontend, and should not call sig.type_infer

What it means

The `#[define_function!]`-style macro lets authors mark a function's type inference as `type_infer = "unreachable"`, generating a closure that panics if invoked. This panic message signals that the function's return type must be inferred by the frontend and `sig.type_infer` must never be called at runtime.

Source

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

            if ret == "auto" {
                ret = types::min_compatible_type(&args);
            }
            let attr = FunctionAttr {
                args: args.iter().map(|s| s.to_string()).collect(),
                ret: ret.to_owned(),
                ..self.clone()
            };
            attrs.push(attr);
        }
        attrs
    }

    /// Generate the type infer function: `fn(&[DataType]) -> Result<DataType>`
    fn generate_type_infer_fn(&self) -> Result<TokenStream2> {
        if let Some(func) = &self.type_infer {
            if func == "unreachable" {
                return Ok(
                    quote! { |_| unreachable!("type inference for this function should be specially handled in frontend, and should not call sig.type_infer") },
                );
            }
            // use the user defined type inference function
            return Ok(func.parse().unwrap());
        } else if self.ret == "any" {
            // TODO: if there are multiple "any", they should be the same type
            if let Some(i) = self.args.iter().position(|t| t == "any") {
                // infer as the type of "any" argument
                return Ok(quote! { |args| Ok(args[#i].clone()) });
            }
            if let Some(i) = self.args.iter().position(|t| t == "anyarray") {
                // infer as the element type of "anyarray" argument
                return Ok(quote! { |args| Ok(args[#i].as_list_elem().clone()) });
            }
        } else if self.ret == "anyarray" {
            if let Some(i) = self.args.iter().position(|t| t == "anyarray") {
                // infer as the type of "anyarray" argument
                return Ok(quote! { |args| Ok(args[#i].clone()) });

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Implement frontend type inference for this function so the backend infer path is never used
  2. Change the macro declaration to provide a real `type_infer = "|args| Ok(...)"` closure
  3. Trace the caller of sig.type_infer and route it to the frontend-specialized path

Example fix

// before
TypeInfer::Unreachable
// after
TypeInfer::from_closure(|args| Ok(DataType::Varchar)) // or implement frontend inference
Defensive patterns

Strategy: validation

Validate before calling

// before registering a function with type_infer = "unreachable", assert the frontend infers its type:
assert!(frontend_infer_return_type(func_id, arg_types).is_ok(), "frontend must infer this function's type");

Try / catch

match sig.type_infer(args) {
    Err(e) if e.to_string().contains("specially handled in frontend") => frontend_infer_return_type(func_id, args),
    other => other,
}

Prevention

When it happens

Trigger: Calling type inference at runtime on a function descriptor generated with `type_infer = "unreachable"` — i.e. a function whose return type depends on arguments (e.g. casts, array elem access) that the frontend must resolve specially.

Common situations: Adding a new function with `unreachable` inference but forgetting to register frontend type inference; batch/stream executor falling back to generic inference for such a function.

Related errors


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