{"record":{"id":"08c48bce906cd27c","repo":"risingwavelabs/risingwave","slug":"fetch-finished-actors-mismatch-expected-ac","errorCode":null,"errorMessage":"fetch finished actors mismatch: expected: {:?}, actual: {:?}","messagePattern":"fetch finished actors mismatch: expected: (.+?), actual: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/refresh_manager.rs","lineNumber":567,"sourceCode":"                    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)\n            } else {\n                Err(MetaError::from(anyhow!(\n                    \"fetch finished actors mismatch: expected: {:?}, actual: {:?}\",\n                    self.expected_fetch_actors,\n                    self.fetch_finished_actors\n                )))\n            }\n        } else {\n            Ok(false)\n        }\n    }\n}\n","sourceCodeStart":549,"sourceCodeEnd":578,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/refresh_manager.rs#L549-L578","documentation":"`is_load_finished` mirrors the list-phase check for the fetch/load phase: when the number of fetch-finished actors reaches the expected count, the actual `fetch_finished_actors` set must equal `expected_fetch_actors`. If not, the recorded completion set has drifted from the plan, and the manager throws this error rather than reporting the load phase as done. It protects against completing a refresh on partially or wrongly tracked actor completion.","triggerScenarios":"Calling `is_load_finished` when `fetch_finished_actors.len() >= expected_fetch_actors.len()` but the sets differ — e.g. notifications for actors no longer in the expected plan, duplicates counted via len(), or the expected plan was updated mid-flight.","commonSituations":"A reschedule changed the actor layout while old fetch-finish reports were still queued; a source/backfill actor reported completion out of band; repeated refresh invocations sharing stale state.","solutions":["Compare the logged expected vs actual fetch-finished actor sets to find the offending ids and the pass that recorded them.","Retry the refresh so the manager is recreated with a coherent expected set.","Ensure no concurrent reschedule mutates expected_fetch_actors while fetch is in progress.","If reproducible, file a meta bug: this is an internal bookkeeping inconsistency, not operator error."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match manager.is_load_finished() {\n    Ok(true) => complete_refresh(),\n    Ok(false) => keep_polling(),\n    Err(e) => { warn!(\"fetch bookkeeping drift: {e}\"); rebuild_manager_and_retry(); }\n}","preventionTips":["Serialize refresh and reschedule operations on the same job.","Discard stale fetch-finish notifications after any plan change.","Treat the expected set as immutable during a refresh round.","Add logging of expected vs actual sets on every poll to ease diagnosis."],"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"}