{"record":{"id":"ccf23c4a54a5c83f","repo":"risingwavelabs/risingwave","slug":"should-not-get-split-info-from-incomplete-source-s","errorCode":null,"errorMessage":"Should not get split info from incomplete source scan info","messagePattern":"Should not get split info from incomplete source scan info","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/frontend/src/scheduler/plan_fragmenter.rs","lineNumber":373,"sourceCode":"\nimpl SourceScanInfo {\n    pub fn new(fetch_info: SourceFetchInfo) -> Self {\n        Self::Incomplete(fetch_info)\n    }\n\n    pub async fn complete(self, batch_parallelism: usize) -> SchedulerResult<Self> {\n        match self {\n            SourceScanInfo::Incomplete(fetch_info) => fetch_info.complete(batch_parallelism).await,\n            SourceScanInfo::Unpartitioned(data) => data.complete(batch_parallelism),\n            SourceScanInfo::Complete(_) => {\n                unreachable!(\"Never call complete when SourceScanInfo is already complete\")\n            }\n        }\n    }\n\n    pub fn split_info(&self) -> SchedulerResult<&Vec<SplitImpl>> {\n        match self {\n            Self::Incomplete(_) => Err(SchedulerError::Internal(anyhow!(\n                \"Should not get split info from incomplete source scan info\"\n            ))),\n            Self::Unpartitioned(_) => Err(SchedulerError::Internal(anyhow!(\n                \"Should not get split info from unpartitioned source scan info\"\n            ))),\n            Self::Complete(split_info) => Ok(split_info),\n        }\n    }\n}\n\nimpl UnpartitionedData {\n    fn complete(self, batch_parallelism: usize) -> SchedulerResult<SourceScanInfo> {\n        let splits = match self {\n            UnpartitionedData::Iceberg { task, limit } => {\n                IcebergScanTaskPlanner::plan_splits(task, batch_parallelism, limit)?\n                    .into_iter()\n                    .map(SplitImpl::Iceberg)\n                    .collect()","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/frontend/src/scheduler/plan_fragmenter.rs#L355-L391","documentation":"`SourceScanInfo::split_info` (src/frontend/src/scheduler/plan_fragmenter.rs:373) returns the splits only when the scan info is in the `Complete` state. Calling it on an `Incomplete` variant returns an `SchedulerError::Internal` because splits have not yet been enumerated — the caller violated the expected state transition (complete the source scan first).","triggerScenarios":"Calling `source_scan_info.split_info()` before the fragmenter finished split enumeration for a partitionable source (e.g. during scheduling of a source scan whose `complete()` step was skipped or failed).","commonSituations":"Internal scheduling bugs where `IncompleteSourceScanInfo` is carried into split-consuming code paths, e.g. after a connector split-listing failure left the scan info incomplete.","solutions":["Ensure the source scan info is driven through `complete()` before reading `split_info()`.","Check why split enumeration failed earlier — fix the underlying connector/split-listing error.","Match on the enum (`Complete`) in caller code instead of assuming completeness.","Report if triggered by a stock query — it is a state-machine violation in the scheduler."],"exampleFix":"// before\nlet splits = source_scan_info.split_info()?;\n// after\nlet splits = match source_scan_info {\n    SourceScanInfo::Complete(_) => source_scan_info.split_info()?,\n    _ => return Err(anyhow!(\"source scan not completed before scheduling\")),\n};","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn is_complete(info: &SourceScanInfo) -> bool {\n    matches!(info, SourceScanInfo::Complete(_))\n}","tryCatchPattern":"match source_scan_info {\n    SourceScanInfo::Complete(_) => source_scan_info.split_info()?,\n    SourceScanInfo::Incomplete(_) => return Err(anyhow!(\"source scan incomplete; complete() first\")),\n    _ => Default::default(),\n}","preventionTips":["Always call complete() before reading split info.","Match on the enum instead of assuming Complete.","Fail fast on connector split-listing errors instead of carrying Incomplete state forward."],"tags":["scheduler","plan-fragmenter","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}