{"record":{"id":"26b20fdc8052382e","repo":"xai-org/grok-build","slug":"resources-persistence-writer-stopped","errorCode":null,"errorMessage":"resources persistence writer stopped","messagePattern":"resources persistence writer stopped","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-tools/src/persistence.rs","lineNumber":167,"sourceCode":"\n    /// Replace pending snapshots, write this snapshot, and acknowledge the result.\n    pub fn enqueue_save_and_flush(\n        &self,\n        snapshot: serde_json::Value,\n    ) -> io::Result<tokio::sync::oneshot::Receiver<io::Result<()>>> {\n        if self.state_path.is_none() {\n            let (respond_to, response) = tokio::sync::oneshot::channel();\n            let _ = respond_to.send(Ok(()));\n            return Ok(response);\n        }\n        let (respond_to, response) = tokio::sync::oneshot::channel();\n        self.tx\n            .send(ResourcesPersistenceCommand::SaveAndFlush {\n                snapshot,\n                respond_to,\n            })\n            .map_err(|_| {\n                io::Error::new(\n                    io::ErrorKind::BrokenPipe,\n                    \"resources persistence writer stopped\",\n                )\n            })?;\n        Ok(response)\n    }\n\n    /// Await an acknowledgement returned by [`Self::enqueue_save_and_flush`].\n    pub async fn await_save_and_flush(\n        response: tokio::sync::oneshot::Receiver<io::Result<()>>,\n    ) -> io::Result<()> {\n        response.await.map_err(|_| {\n            io::Error::new(\n                io::ErrorKind::BrokenPipe,\n                \"resources persistence writer dropped acknowledgement\",\n            )\n        })?\n    }","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-tools/src/persistence.rs#L149-L185","documentation":"enqueue_save_and_flush sends a SaveAndFlush command to the resources persistence writer over an mpsc channel; if the send fails because the receiver (writer task) has been dropped/stopped, it maps the SendError to io::ErrorKind::BrokenPipe with the message \"resources persistence writer stopped\". Called by save_and_flush, it means no persistence request can currently be delivered.","triggerScenarios":"Calling save_and_flush/enqueue_save_and_flush after the persistence writer task has been shut down or joined (e.g. after a stop()/shutdown of the scheduler, or the writer panicked and its loop exited).","commonSituations":"Attempting to persist state during application shutdown after the writer was already stopped; a writer panic killed the task; calling the persistence handle from a different part of the app that outlives the scheduler.","solutions":["Restart or recreate the persistence writer before attempting further saves.","Check writer task logs for a panic that ended its loop and fix the underlying cause.","Serialize shutdown so save_and_flush is never called after the writer is stopped (drain saves first).","Handle BrokenPipe gracefully by falling back to a direct (non-actor) write or deferring persistence."],"exampleFix":"// before\nwriter.save_and_flush(snapshot).await?;\n// after\nmatch writer.save_and_flush(snapshot).await {\n    Ok(()) => {},\n    Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => {\n        tracing::warn!(\"persistence writer stopped; writing directly\");\n        write_snapshot_direct(&path, &snapshot).await?;\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"fallback","validationCode":"if writer.is_stopped() {\n    return Err(MyError::PersistenceUnavailable);\n}","typeGuard":null,"tryCatchPattern":"match persistence.save_and_flush(snapshot).await {\n    Ok(()) => {},\n    Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => {\n        fallback_direct_write(&path, &snapshot).await?;\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Establish an ownership rule: only the scheduler issues saves and stops the writer, in that order.","Catch panics in the writer task so a single bad write does not stop it.","Persist critical snapshots before shutdown begins.","Alert/log on BrokenPipe so the stopped writer is noticed immediately."],"tags":["persistence","broken-pipe","channel-closed","shutdown"],"backgroundTag":"persistence-writer-stopped","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}