risingwavelabs/risingwave · error
unspecified type of `RowsFrameBound`
Error message
unspecified type of `RowsFrameBound`
What it means
`RowsFrameBound::from_protobuf` matches the protobuf bound type enum exhaustively; the `Unspecified` variant (proto3 default for unset enum fields) is not a valid frame bound type, so it is rejected. This guards against deserializing a frame bound whose `type` field was never set.
Source
Thrown at src/expr/core/src/window_function/rows.rs:110
impl RowsFrameBound {
pub(super) fn from_protobuf_legacy(bound: &PbBound) -> Result<Self> {
use risingwave_pb::expr::window_frame::bound::PbOffset;
let offset = bound.get_offset()?;
let bound = match offset {
PbOffset::Integer(offset) => Self::from_protobuf(&PbRowsFrameBound {
r#type: bound.get_type()? as _,
offset: Some(*offset),
})?,
PbOffset::Datum(_) => bail!("offset of `RowsFrameBound` must be `Integer`"),
};
Ok(bound)
}
fn from_protobuf(bound: &PbRowsFrameBound) -> Result<Self> {
let bound = match bound.get_type()? {
PbBoundType::Unspecified => bail!("unspecified type of `RowsFrameBound`"),
PbBoundType::UnboundedPreceding => Self::UnboundedPreceding,
PbBoundType::Preceding => Self::Preceding(*bound.get_offset()? as usize),
PbBoundType::CurrentRow => Self::CurrentRow,
PbBoundType::Following => Self::Following(*bound.get_offset()? as usize),
PbBoundType::UnboundedFollowing => Self::UnboundedFollowing,
};
Ok(bound)
}
fn to_protobuf(&self) -> PbRowsFrameBound {
let (r#type, offset) = match self {
Self::UnboundedPreceding => (PbBoundType::UnboundedPreceding, None),
Self::Preceding(offset) => (PbBoundType::Preceding, Some(*offset as _)),
Self::CurrentRow => (PbBoundType::CurrentRow, None),
Self::Following(offset) => (PbBoundType::Following, Some(*offset as _)),
Self::UnboundedFollowing => (PbBoundType::UnboundedFollowing, None),
};
PbRowsFrameBound {View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure the frontend sets `r#type` to one of UnboundedPreceding/Preceding/CurrentRow/Following/UnboundedFollowing before serialization
- Regenerate the plan with a matching frontend version
- Validate the plan fragment before deserialization
Example fix
// before (proto)
// rows_frame_bound { offset: 3 } // type unset -> UNSPECIFIED
// after (proto)
// rows_frame_bound { type: PRECEDING, offset: 3 } Defensive patterns
Strategy: validation
Validate before calling
fn bound_type_set(t: i32) -> bool { t != 0 } // 0 = UNSPECIFIED Type guard
fn is_specified(t: PbBoundType) -> bool { !matches!(t, PbBoundType::Unspecified) } Try / catch
match RowsFrameBound::from_protobuf(&pb) {
Ok(b) => b,
Err(e) if e.to_string().contains("unspecified type") => return Err(anyhow!("frame bound type missing in plan")),
Err(e) => return Err(e.into()),
} Prevention
- Always set `r#type` explicitly when constructing PbRowsFrameBound
- Enable proto linting that rejects enum field defaults
- Round-trip test plans through serialize/deserialize
When it happens
Trigger: Deserializing a `PbRowsFrameBound` where `r#type` is UNSPECIFIED (0) — i.e. the field was omitted or defaulted in the serialized plan.
Common situations: Protobuf messages constructed programmatically without setting the type field; older/other producers that don't populate required enums; corrupted plan fragments.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- unspecified type of `WindowFrame`
- unspecified type of `FrameExclusion`
- Unspecified window function type
- no such window function type
- unspecified type of `RangeFrameBound`
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/49bd835c129aeb18.
Report an issue: GitHub.