risingwavelabs/risingwave · error

Node {} cannot be convert to batch node

Error message

Node {} cannot be convert to batch node

What it means

TryToBatchPb::try_to_batch_prost_body is a default trait method that always returns this error: it exists so that only batch plan nodes can be converted to a protobuf BatchNode body. Calling it on a non-batch (stream) plan node hits the default implementation, which converts the original panic into a SchedulerResult error.

Source

Thrown at src/frontend/src/optimizer/plan_node/to_prost.rs:25

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::anyhow;
use risingwave_pb::batch_plan::plan_node as pb_batch_node;
use risingwave_pb::stream_plan::stream_node as pb_stream_node;

use super::*;

pub trait TryToBatchPb {
    fn try_to_batch_prost_body(&self) -> SchedulerResult<pb_batch_node::NodeBody> {
        // Originally we panic in the following way
        // panic!("convert into distributed is only allowed on batch plan")
        Err(anyhow!(
            "Node {} cannot be convert to batch node",
            std::any::type_name::<Self>()
        )
        .into())
    }
}

pub trait ToBatchPb {
    fn to_batch_prost_body(&self) -> pb_batch_node::NodeBody;
}

impl<T: ToBatchPb> TryToBatchPb for T {
    fn try_to_batch_prost_body(&self) -> SchedulerResult<pb_batch_node::NodeBody> {
        Ok(self.to_batch_prost_body())
    }
}

pub trait TryToStreamPb {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Verify the code path is converting a batch plan, not a stream plan, to prost.
  2. Implement TryToBatchPb for the concrete plan node type (add a try_to_batch_prost_body override).
  3. If this is unexpected at runtime, fix the optimizer dispatch so batch plans reach ToBatchProst and stream plans reach ToStreamProst.

Example fix

// before
// no impl, falls into default error
impl TryToBatchPb for MyJoinNode {}
// after
impl TryToBatchPb for MyJoinNode {
    fn try_to_batch_prost_body(&self) -> SchedulerResult<pb_batch_node::NodeBody> {
        Ok(pb_batch_node::NodeBody::HashJoin(self.to_batch_hash_join_prost()?))
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure node kind is batch before conversion
if !matches!(plan_node, PlanNode::Batch(_)) { return Err(anyhow!("expected batch plan node")); }

Type guard

fn as_batch(node: &PlanRef) -> Option<&BatchPlanNode> { node.as_batch() }

Try / catch

match node.try_to_batch_prost_body() {
    Ok(body) => body,
    Err(e) if e.to_string().contains("cannot be convert to batch node") => fallback_to_stream_pipeline_or_bug_report(e),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling try_to_batch_prost_body() on a plan node that has not overridden the trait method (any stream-only or generic plan node), typically during distributed batch query planning when the optimizer hands a stream plan to the batch plan-to-prost serializer.

Common situations: A developer adds a new plan node but forgets to implement TryToBatchPb; an internal bug routes a stream plan through the batch scheduler path.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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