{"record":{"id":"b598601d31258c23","repo":"risingwavelabs/risingwave","slug":"receive-shutdown-msg-msg","errorCode":null,"errorMessage":"Receive shutdown msg: {msg:?}","messagePattern":"Receive shutdown msg: (.+?)","errorType":"error_code","errorClass":"BatchError","httpStatus":null,"severity":"warning","filePath":"src/batch/src/task/task_execution.rs","lineNumber":271,"sourceCode":"pub struct ShutdownToken(tokio::sync::watch::Receiver<ShutdownMsg>);\n\nimpl ShutdownToken {\n    /// Create an empty token.\n    pub fn empty() -> Self {\n        Self::new().1\n    }\n\n    /// Create a new token.\n    pub fn new() -> (ShutdownSender, Self) {\n        let (tx, rx) = tokio::sync::watch::channel(ShutdownMsg::Init);\n        (ShutdownSender(tx), ShutdownToken(rx))\n    }\n\n    /// Return error if the shutdown token has been triggered.\n    pub fn check(&self) -> Result<()> {\n        match &*self.0.borrow() {\n            ShutdownMsg::Init => Ok(()),\n            msg => bail!(\"Receive shutdown msg: {msg:?}\"),\n        }\n    }\n\n    /// Wait until cancellation is requested.\n    ///\n    /// # Cancel safety\n    /// This method is cancel safe.\n    pub async fn cancelled(&mut self) {\n        if matches!(*self.0.borrow(), ShutdownMsg::Init)\n            && let Err(_err) = self.0.changed().await\n        {\n            std::future::pending::<()>().await;\n        }\n    }\n\n    /// Return true if the shutdown token has been triggered.\n    pub fn is_cancelled(&self) -> bool {\n        !matches!(*self.0.borrow(), ShutdownMsg::Init)","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/batch/src/task/task_execution.rs#L253-L289","documentation":"The batch task's `ShutdownMonitor::check` found that a shutdown/cancellation message (other than `Init`) has been recorded — e.g. the task was cancelled, aborted, or the system is shutting down — and bails with \"Receive shutdown msg: {msg:?}\". Join executors call this between poll steps to abort promptly instead of continuing to produce output for a task that is being torn down.","triggerScenarios":"Raised by `ShutdownMonitor::check` (src/batch/src/task/task_execution.rs:271), called from the join executor polling loops (`do_inner_join`, `do_left_outer_join`, `do_left_semi_anti_join`, `do_right_outer_join`, `do_right_semi_anti_join`, `do_full_outer_join`). It fires when `ShutdownMsg` has transitioned from `Init` — via `request_shutdown`/cancellation token triggered by the task manager (query cancelled, task aborted, epoch timeout) or cluster shutdown — and the join loop next calls `check()`.","commonSituations":"A user cancels a long-running query in psql; the frontend/meta node aborts a stage (e.g. one node failed, killing sibling tasks); the batch task hits an epoch/time limit; RisingWave cluster shutdown while a join is mid-scan. Usually expected behavior during cancellation, but appearing without user cancellation suggests the task manager is aborting the stage (check for a sibling task failure).","solutions":["Check whether the query was cancelled (user CANCEL QUERY, timeout, or `error while restarting`-style shutdown); if so this error is expected and can be ignored.","Look for sibling task/stage failures around the same timestamp — the task manager aborts all tasks of a failing stage, making this error secondary.","If it fires spuriously, inspect shutdown-token lifecycle in the task environment (premature `request_shutdown` or reused task env).","Retry the query if it was killed by cluster shutdown or failover."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Callers treat shutdown as cancellation: map it to a cancelled/aborted error, not a data error\nif let Err(e) = monitor.check() {\n    tracing::info!(\"task aborted during join: {e}\");\n    return Err(e.into()); // task manager already knows; do not retry within the task\n}","preventionTips":["Avoid long-running un-cancellable work between check() calls so cancellation stays responsive","If you see this without user cancellation, look for sibling stage/task failures triggering an abort","In client code, treat this as expected on query cancel/timeout and retry idempotent queries","Check shutdown-token ownership if this fires during normal completion"],"tags":["batch","cancellation","task-execution"],"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"}