cube-js/cube · error · syn::Error

Return type should be Result<_>

Error message

Return type should be Result<_>

What it means

get_deserializer_output_for_result inspects the last path segment of the return type and requires that it exists and is `Result`. If the segments are empty (malformed/edge-case path) the ok_or fallback emits 'Return type should be Result<_>'. This is the guard ensuring every bridged method's output is a Result-shaped wrapper before deserializing its inner type.

Source

Thrown at rust/cube/cubesqlplanner/nativebridge/src/lib.rs:256

                    let segs = &tp.path.segments;
                    Self::get_deserializer_output_for_result(segs, optional, vec, &expected_type)
                }
                _ => Err(syn::Error::new(
                    tp.span(),
                    format!("Return type should be {}", expected_type),
                )),
            },
        };
        s
    }

    fn get_deserializer_output_for_result(
        segs: &Punctuated<PathSegment, PathSep>,
        optional: bool,
        vec: bool,
        expected_type: &str,
    ) -> syn::Result<NativeOutputParams> {
        let seg = segs.last().ok_or(syn::Error::new(
            segs.span(),
            "Return type should be Result<_>",
        ))?;
        if seg.ident.to_string() == "Result" {
            let mut args = seg.arguments.clone();
            if optional {
                args = Self::extract_output_for_nested_type(&args, "Option", expected_type)?;
            }
            if vec {
                args = Self::extract_output_for_nested_type(&args, "Vec", expected_type)?;
            }
            Self::get_type_for_deserialize_from_result_args(&args, expected_type)
        } else {
            Err(syn::Error::new(
                seg.span(),
                "Return type should be Result<_>",
            ))
        }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Return a plain `Result<T>` (possibly `Result<Option<T>>` / `Result<Vec<T>>`) from the bridged method.
  2. Avoid deeply nested or aliased exotic type paths in bridge method signatures.
  3. If using type aliases, expand them to the concrete Result shape in the trait signature.

Example fix

// before
type Out = std::result::Result<String, Error>;
fn query(&self) -> Out;

// after
fn query(&self) -> Result<String>;
Defensive patterns

Strategy: validation

Validate before calling

// Expand aliases: keep the literal Result<...> in the signature
fn uses_literal_result(sig: &str) -> bool {
    sig.contains("-> Result<")
}
// assert!(uses_literal_result("fn q(&self) -> Result<String>;"));

Prevention

When it happens

Trigger: A return type whose path resolves with no final segment when reaching this helper — practically seen with unusual type paths or when this function is invoked on segments extracted from a type that is not a plain wrapper.

Common situations: Rare; usually encountered when the macro's type parsing is fed an exotic path type or after refactoring return types into aliases the macro cannot resolve.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/5562c5d458cf7820. Report an issue: GitHub.