{"record":{"id":"e9aef98ce9cef713","repo":"risingwavelabs/risingwave","slug":"list-finished-actors-mismatch-expected-act","errorCode":null,"errorMessage":"list finished actors mismatch: expected: {:?}, actual: {:?}","messagePattern":"list finished actors mismatch: expected: (.+?), actual: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/refresh_manager.rs","lineNumber":547,"sourceCode":"        Self {\n            expected_list_actors: HashSet::new(),\n            expected_fetch_actors: HashSet::new(),\n            list_finished_actors: HashSet::new(),\n            fetch_finished_actors: HashSet::new(),\n            start_time: Instant::now(),\n        }\n    }\n\n    pub fn report_list_finished(&mut self, actor_ids: impl Iterator<Item = ActorId>) {\n        self.list_finished_actors.extend(actor_ids);\n    }\n\n    pub fn is_list_finished(&self) -> MetaResult<bool> {\n        if self.list_finished_actors.len() >= self.expected_list_actors.len() {\n            if self.expected_list_actors == self.list_finished_actors {\n                Ok(true)\n            } else {\n                Err(MetaError::from(anyhow!(\n                    \"list finished actors mismatch: expected: {:?}, actual: {:?}\",\n                    self.expected_list_actors,\n                    self.list_finished_actors\n                )))\n            }\n        } else {\n            Ok(false)\n        }\n    }\n\n    pub fn report_load_finished(&mut self, actor_ids: impl Iterator<Item = ActorId>) {\n        self.fetch_finished_actors.extend(actor_ids);\n    }\n\n    pub fn is_load_finished(&self) -> MetaResult<bool> {\n        if self.fetch_finished_actors.len() >= self.expected_fetch_actors.len() {\n            if self.expected_fetch_actors == self.fetch_finished_actors {\n                Ok(true)","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/refresh_manager.rs#L529-L565","documentation":"In the streaming job refresh manager, `is_list_finished` validates that the set of actors whose list phase finished (`list_finished_actors`) exactly equals the expected set (`expected_list_actors`). Once the reported count reaches the expected count, the two sets are compared; any divergence (extra, missing, or wrong actor ids) means the refresh bookkeeping is inconsistent, so the meta service raises this error instead of declaring the phase complete. It is an internal consistency check on reschedule/refresh progress.","triggerScenarios":"Calling `is_list_finished` on a `RefreshManager` when `list_finished_actors.len() >= expected_list_actors.len()` but the two sets differ — e.g. duplicate or stale actor ids were recorded as list-finished, or the expected set changed (new reschedule) while in-flight notifications from the old plan kept arriving.","commonSituations":"Race during a reschedule where the expected actor list is regenerated while finish notifications for old actors are still being recorded; a bug in the notification path reporting the wrong actor ids; concurrent refresh attempts sharing the same manager state.","solutions":["Inspect the logged expected vs actual actor id sets to identify the stray or missing actor and trace which reschedule pass recorded it.","Retry the refresh/reschedule operation so the manager is rebuilt from a consistent expected-actor snapshot.","Check for concurrent reschedules/refreshes on the same table/job and serialize them.","If reproducible, report as a meta bug — the mismatch implies broken bookkeeping in the refresh manager rather than user error."],"exampleFix":"// before: recording finish notifications without matching against the current expected set\nmanager.record_list_finished(actor_id);\n// after: only record ids that belong to the current expected plan\nif manager.expected_list_actors().contains(&actor_id) {\n    manager.record_list_finished(actor_id);\n}","handlingStrategy":"try-catch","validationCode":"// before calling, ensure no reschedule is in flight and the manager was freshly built\nassert!(expected.iter().all(|a| !reported.contains(a)) || expected == reported);","typeGuard":null,"tryCatchPattern":"match manager.is_list_finished() {\n    Ok(true) => proceed_to_next_phase(),\n    Ok(false) => keep_polling(),\n    Err(e) => log_error_and_retry_refresh(e), // rebuild the refresh manager and retry\n}","preventionTips":["Never run concurrent reschedules/refreshes on the same streaming job.","Rebuild the refresh manager whenever the expected actor plan changes.","Filter finish notifications against the current expected actor set before recording.","Monitor for this error and alert — it indicates meta bookkeeping bugs, not operator mistakes."],"tags":["streaming-meta","reschedule","consistency"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}