risingwavelabs/risingwave · error

Should not get split info from unpartitioned source scan inf

Error message

Should not get split info from unpartitioned source scan info

What it means

`SourceScanInfo::split_info` (src/frontend/src/scheduler/plan_fragmenter.rs:376) errors when called on the `Unpartitioned` variant. Unpartitioned sources have no per-split parallelism, so there is no `Vec<SplitImpl>` to return; only `Complete` sources expose split info.

Source

Thrown at src/frontend/src/scheduler/plan_fragmenter.rs:376

        Self::Incomplete(fetch_info)
    }

    pub async fn complete(self, batch_parallelism: usize) -> SchedulerResult<Self> {
        match self {
            SourceScanInfo::Incomplete(fetch_info) => fetch_info.complete(batch_parallelism).await,
            SourceScanInfo::Unpartitioned(data) => data.complete(batch_parallelism),
            SourceScanInfo::Complete(_) => {
                unreachable!("Never call complete when SourceScanInfo is already complete")
            }
        }
    }

    pub fn split_info(&self) -> SchedulerResult<&Vec<SplitImpl>> {
        match self {
            Self::Incomplete(_) => Err(SchedulerError::Internal(anyhow!(
                "Should not get split info from incomplete source scan info"
            ))),
            Self::Unpartitioned(_) => Err(SchedulerError::Internal(anyhow!(
                "Should not get split info from unpartitioned source scan info"
            ))),
            Self::Complete(split_info) => Ok(split_info),
        }
    }
}

impl UnpartitionedData {
    fn complete(self, batch_parallelism: usize) -> SchedulerResult<SourceScanInfo> {
        let splits = match self {
            UnpartitionedData::Iceberg { task, limit } => {
                IcebergScanTaskPlanner::plan_splits(task, batch_parallelism, limit)?
                    .into_iter()
                    .map(SplitImpl::Iceberg)
                    .collect()
            }
        };
        Ok(SourceScanInfo::Complete(splits))

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check `SourceScanInfo` variant before calling `split_info()` and handle `Unpartitioned` with a parallelism-1 schedule.
  2. Verify the source kind supports partitioned batch reads; use a table/MV over the source if you need queryable splits.
  3. Fix the caller (fragmenter/scheduler) to branch on the enum state instead of unconditionally requesting splits.

Example fix

// before
let splits = source_scan_info.split_info()?;
// after
let splits = match &source_scan_info {
    SourceScanInfo::Complete(_) => source_scan_info.split_info()?,
    SourceScanInfo::Unpartitioned(_) | SourceScanInfo::Incomplete(_) => {
        Default::default() // no parallel splits
    }
};
Defensive patterns

Strategy: type-guard

Type guard

fn splits_available(info: &SourceScanInfo) -> bool {
    matches!(info, SourceScanInfo::Complete(_))
}

Try / catch

let splits = match &source_scan_info {
    SourceScanInfo::Complete(_) => source_scan_info.split_info()?,
    SourceScanInfo::Unpartitioned(_) => return Ok(parallelism_one_schedule()),
    SourceScanInfo::Incomplete(_) => return Err(anyhow!("incomplete scan info")),
};

Prevention

When it happens

Trigger: Calling `split_info()` on a source scan info produced for an unpartitioned source (e.g. Datagen, or single-node sources) instead of a partitioned source like Kafka or an Iceberg/File scan.

Common situations: Scheduler code paths assuming all source scans are partitionable, executed against sources like datagen or system sources where parallel split scheduling does not apply.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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