{"record":{"id":"6bdff1bbb4e947b4","repo":"cube-js/cube","slug":"cachestore-cannot-be-used-on-the-worker-node-pers","errorCode":null,"errorMessage":"CacheStore cannot be used on the worker node! persist was used.","messagePattern":"CacheStore cannot be used on the worker node! persist was used\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust/cubestore/cubestore/src/cachestore/cache_rocksstore.rs","lineNumber":2088,"sourceCode":"\n    async fn queue_merge_extra(&self, _key: QueueKey, _payload: String) -> Result<(), CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! queue_merge_extra was used.\")\n    }\n\n    async fn compaction(&self) -> Result<(), CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! compaction was used.\")\n    }\n\n    async fn info(&self) -> Result<CachestoreInfo, CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! info was used.\")\n    }\n\n    async fn eviction(&self) -> Result<EvictionResult, CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! eviction was used.\")\n    }\n\n    async fn persist(&self) -> Result<(), CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! persist was used.\")\n    }\n\n    async fn healthcheck(&self) -> Result<(), CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! healthcheck was used.\")\n    }\n\n    async fn rocksdb_properties(&self) -> Result<Vec<RocksPropertyRow>, CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! rocksdb_properties was used.\")\n    }\n\n    async fn wipe(&self) -> Result<(), CubeError> {\n        panic!(\"CacheStore cannot be used on the worker node! wipe was used.\")\n    }\n}\n\ncrate::di_service!(ClusterCacheStoreClient, [CacheStore]);\n\n#[cfg(test)]","sourceCodeStart":2070,"sourceCodeEnd":2106,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/rust/cubestore/cubestore/src/cachestore/cache_rocksstore.rs#L2070-L2106","documentation":"CacheStore::persist flushes cache metadata to disk; on worker nodes it is a panic! stub (cache_rocksstore.rs:2088) because persistence belongs to the master store. The panic guards against persistence attempts through a cache-only worker store.","triggerScenarios":"Calling CacheStore::persist() on a worker-node CacheStore instance (cache_rocksstore.rs:2088), e.g. from a periodic flush task or shutdown hook.","commonSituations":"Shutdown hooks and flush timers installed on every node regardless of role; code shared between master and worker binaries invoking persist unconditionally.","solutions":["Invoke persist only on the master node's store","Gate flush/shutdown logic with a node-role check","Ensure worker processes do not register master-only persistence hooks"],"exampleFix":"// before\n// shutdown hook on every node\nstore.persist().await?;\n// after\nif is_master { store.persist().await?; }","handlingStrategy":"validation","validationCode":"if !is_master { return Err(CubeError::internal(\"persist is master-only\")); }\nmaster_client.persist().await?;","typeGuard":"fn supports_persist(store: &dyn CacheStore) -> bool { node_role == NodeRole::Master }","tryCatchPattern":"std::panic::catch_unwind(AssertUnwindSafe(|| master_client.persist())).map_err(|_| CubeError::internal(\"persist called on worker node\"))?;","preventionTips":["Install flush/persist hooks only in master processes","Check role in shutdown handlers","Avoid shared hooks that call persist unconditionally","Gate periodic flush timers by node role"],"tags":["cubestore","rust","panic","cache-store","worker-node","persist"],"backgroundTag":"cachestore-not-usable-on-worker","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}