risingwavelabs/risingwave · error · BatchError
unspecified AsOf join inequality type
Error message
unspecified AsOf join inequality type
What it means
When deserializing an AsOf join inequality descriptor from its protobuf representation, the `inequality_type` field was `AsOfInequalityTypeUnspecified`. RisingWave requires an explicit inequality (Lt, Le, Gt, or Ge) to perform an ASOF join, so the batch executor builder rejects the plan instead of guessing. This is a plan-serialization/validation failure, not a runtime data issue.
Source
Thrown at src/batch/executors/src/executor/join/mod.rs:117
Gt,
}
#[derive(Clone, Debug)]
pub struct AsOfDesc {
pub left_idx: usize,
pub right_idx: usize,
pub inequality_type: AsOfInequalityType,
}
impl AsOfDesc {
pub fn from_protobuf(desc_proto: &AsOfJoinDesc) -> crate::error::Result<Self> {
let typ = match desc_proto.inequality_type() {
AsOfJoinInequalityType::AsOfInequalityTypeLt => AsOfInequalityType::Lt,
AsOfJoinInequalityType::AsOfInequalityTypeLe => AsOfInequalityType::Le,
AsOfJoinInequalityType::AsOfInequalityTypeGt => AsOfInequalityType::Gt,
AsOfJoinInequalityType::AsOfInequalityTypeGe => AsOfInequalityType::Ge,
AsOfJoinInequalityType::AsOfInequalityTypeUnspecified => {
bail!("unspecified AsOf join inequality type")
}
};
Ok(Self {
left_idx: desc_proto.left_idx as usize,
right_idx: desc_proto.right_idx as usize,
inequality_type: typ,
})
}
}
/// The layout be like:
///
/// [ `left` chunk | `right` chunk ]
///
/// # Arguments
///
/// * `left` Data chunk padded to the left half of result data chunk..
/// * `right` Data chunk padded to the right half of result data chunk.View on GitHub (pinned to 6469eb736d)
Solutions
- Upgrade all RisingWave nodes (frontend, meta, compute) to the same version so ASOF join descriptors always serialize inequality_type.
- Check the plan serialization path that produced the AsOfJoinDesc and ensure `set_inequality_type` is called with Lt/Le/Gt/Ge before sending.
- Regenerate/rebuild the protobuf code if a custom client constructs the plan, confirming the field is populated (proto3 does not send default values).
Example fix
// before (client building the descriptor)
let desc = pb::AsOfJoinDesc { left_idx: 1, right_idx: 2, inequality_type: Default::default() };
// after
use pb::AsOfJoinInequalityType;
let desc = pb::AsOfJoinDesc { left_idx: 1, right_idx: 2, inequality_type: AsOfJoinInequalityType::AsOfInequalityTypeLe as i32 }; Defensive patterns
Strategy: validation
Validate before calling
// before submitting the plan, verify the descriptor is fully populated
fn validate_asof_desc(desc: &pb::AsOfJoinDesc) -> Result<()> {
let t = AsOfJoinInequalityType::try_from(desc.inequality_type)
.map_err(|_| anyhow!("asof join inequality_type must be set (Lt/Le/Gt/Ge)"))?;
ensure!(t != AsOfJoinInequalityType::AsOfInequalityTypeUnspecified, "inequality_type unspecified");
Ok(())
} Prevention
- Keep frontend, meta, and compute nodes on the same RisingWave version.
- When constructing protobuf plans programmatically, always set every non-optional field explicitly; proto3 omits zero/default values.
- Add a unit test that round-trips AsOfJoinDesc through protobuf for all four inequality types.
When it happens
Trigger: Calling `AsOfJoinDesc::from_protobuf` (via building a batch executor from a plan fragment) where the protobuf `AsOfJoinDesc` message has `inequality_type` left at the default proto3 `Unspecified` value — e.g. the meta/frontend produced or an older binary sent a descriptor without setting the field.
Common situations: Version skew between frontend/meta and compute nodes where one side serializes ASOF joins without the inequality_type field; hand-crafted or fuzzed protobuf plan fragments; proto3 default-value omission when a client builds the plan programmatically.
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 AsOf join inequality type
- MATCH_RECOGNIZE measure missing expression
- invalid MATCH_RECOGNIZE measure slot kind: {}
- MATCH_RECOGNIZE SUM/AVG measure slot missing agg_call
- MATCH_RECOGNIZE define missing condition
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/cd6daa2cddda7486.
Report an issue: GitHub.