diff --git a/algo/kf/core/geo/KfSetupBuilder.cxx b/algo/kf/core/geo/KfSetupBuilder.cxx
index 0d88a20b1c7f89748039e667438338c87587234f..6c300eb53b497a2ede435e70ce3a354cc80889fd 100644
--- a/algo/kf/core/geo/KfSetupBuilder.cxx
+++ b/algo/kf/core/geo/KfSetupBuilder.cxx
@@ -67,6 +67,7 @@ void SetupBuilder::Init()
     }
 
     if (!bMaterialLoaded) {
+      fvMaterial.clear();
       fvMaterial.reserve(fGeoLayers.size());
     }
     double zLast{fTarget.GetZ() + fTarget.GetDz() * kTargetMaterialOffset};
@@ -124,6 +125,15 @@ bool SetupBuilder::LoadMaterial()
   try {
     boost::archive::binary_iarchive ia(ifs);
     MaterialMap targetMat;
+    size_t refHash;
+    ia >> refHash;
+    if (refHash != fGeoHash) {
+      LOG(warn) << "kf::SetupBuilder::LoadMaterial: reference hash from input file \"" << fsMaterialCacheFile
+                << "\" "
+                   "diverges from one, obtained from the actual detector setup geometry. Material budget will be "
+                   "re-generated, and a new file will be created";
+      return false;
+    }
     ia >> targetMat;
     ia >> fvMaterial;
     fTarget.SetMaterial(targetMat);
@@ -195,6 +205,7 @@ void SetupBuilder::StoreMaterial() const
     throw std::runtime_error(msg.str());
   }
   boost::archive::binary_oarchive oa(ofs);
+  oa << fGeoHash;
   oa << fTarget.GetMaterial();
   oa << fvMaterial;
 }
diff --git a/algo/kf/core/geo/KfSetupBuilder.h b/algo/kf/core/geo/KfSetupBuilder.h
index 649f64e279964b3254062819909118c335507337..bebd43ad57779ee75c2d8a0d40bf690efde7e30a 100644
--- a/algo/kf/core/geo/KfSetupBuilder.h
+++ b/algo/kf/core/geo/KfSetupBuilder.h
@@ -122,11 +122,17 @@ namespace cbm::algo::kf
 
     /// \brief Sets the material budget cache file name
     /// \param filename  Material budget cache file name
+    /// \param refHash   Reference hash of the geometry
     ///
     /// If provided, the instance will try to read the material budget maps from the file. If the file does not exist,
     /// or the geometry hash was changed since the last time, the material budget maps will be recreated on the flight
-    /// and stored to the file.
-    void SetMaterialCacheFile(const std::string& filename) { fsMaterialCacheFile = filename; }
+    /// and stored to the file. If the reference hash differs from one, read from the file, a warning will be produced,
+    /// and the new cache file will be generated.
+    void SetMaterialCacheFile(const std::string& filename, size_t refHash)
+    {
+      fsMaterialCacheFile = filename;
+      fGeoHash            = refHash;
+    }
 
     /// \brief Sets target initialization properties
     /// \param x  Target x-coordinate [cm]
@@ -187,6 +193,7 @@ namespace cbm::algo::kf
     ModuleIndexMapFactory fModuleIndexFactory;                           ///< Module index factory
     FieldFactory fFieldFactory;                                          ///< Instance of field factory
     Target<double> fTarget;                                              ///< Target properties
+    size_t fGeoHash{0};                                                  ///< A hash of the geometry
     int fMatMapNofBins{100};                                             ///< Number of bins in material maps
 
     bool fbIfTargetSet{false};         ///< Target initialized
diff --git a/reco/kfnew/CbmKfTrackingSetupBuilder.cxx b/reco/kfnew/CbmKfTrackingSetupBuilder.cxx
index 347f7c6931577ff40b39bc8f6726c92a97fbd114..338a86b63d4ca0ad6974f03ae248b3e5fa91af45 100644
--- a/reco/kfnew/CbmKfTrackingSetupBuilder.cxx
+++ b/reco/kfnew/CbmKfTrackingSetupBuilder.cxx
@@ -25,6 +25,8 @@
 #include "KfMaterialMapFactory.h"
 #include "Logger.h"
 
+#include <boost/filesystem.hpp>
+
 #include <functional>
 
 using cbm::algo::ca::EDetectorID;
@@ -134,20 +136,28 @@ catch (const std::exception& err) {
 //
 TrackingSetupBuilder* TrackingSetupBuilder::Instance()
 {
+  namespace fs = boost::filesystem;
   if (fpInstance == nullptr) {
     std::lock_guard<std::mutex> lock(fMutex);
     fpInstance = new TrackingSetupBuilder{};
     fpInstance->CheckDetectorPresence();
 
+    // Retrieve the geometry tag
     auto setupTag = CbmSetup::Instance()->GetProvider()->GetSetup().GetTag();
     if (setupTag.empty()) {
       throw std::logic_error("The setup tag in CbmSetup is not defined");
     }
-    //TString sinkName = FairRootManager::Instance()->GetSink()->GetFileName();
 
-    // Creating the cache file in "./", so the macros from different directories could use the same file
-    std::string sCacheFile = Form("./%s.mat.kf.bin", setupTag.c_str());
-    fpInstance->SetMaterialCacheFile(sCacheFile);
+    // Retrieve the data directory (the same as for the sink file)
+    TString sinkName     = FairRootManager::Instance()->GetSink()->GetFileName();
+    auto sinkPath        = fs::path{sinkName.Data()};
+    std::string sDataDir = sinkPath.parent_path().string();
+    if (sDataDir.empty()) {
+      sDataDir = ".";
+    }
+
+    std::string sCacheFile = Form("%s/%s.mat.kf.bin", sDataDir.c_str(), setupTag.c_str());
+    fpInstance->SetMaterialCacheFile(sCacheFile, CbmSetup::Instance()->GetHash());
   }
   return fpInstance;
 }
diff --git a/reco/kfnew/CbmKfTrackingSetupBuilder.h b/reco/kfnew/CbmKfTrackingSetupBuilder.h
index a4754c4efee2f0a32a9fd60506281ad701a29a4b..1263cd9e3336865849abb4bd825ce3ece7924cbc 100644
--- a/reco/kfnew/CbmKfTrackingSetupBuilder.h
+++ b/reco/kfnew/CbmKfTrackingSetupBuilder.h
@@ -54,14 +54,6 @@ namespace cbm::kf
     TrackingSetupBuilder& operator=(const TrackingSetupBuilder&) = delete;
     TrackingSetupBuilder& operator=(TrackingSetupBuilder&&) = delete;
 
-    /// \brief  Sets a name for the material budget cache-file
-    /// \param  filename  A name of the file
-    ///
-    /// If provided, the instance will try to read the material budget maps from the file. If the file does not exist,
-    /// or the geometry hash was changed since the last time, the material budget maps will be recreated on the flight
-    /// and stored to the file.
-    void SetMaterialCacheFile(const TString& filename) { fBuilder.SetMaterialCacheFile(filename.Data()); }
-
    private:
     template<typename T>
     using DetectorIDArray_t = cbm::core::EnumArray<cbm::algo::ca::EDetectorID, T>;
@@ -79,6 +71,19 @@ namespace cbm::kf
     /// \brief  Check detector presence
     void CheckDetectorPresence();
 
+    /// \brief Sets the material budget cache file name
+    /// \param filename  Material budget cache file name
+    /// \param geoHash   A hash of the geometry
+    ///
+    /// If provided, the instance will try to read the material budget maps from the file. If the file does not exist,
+    /// or the geometry hash was changed since the last time, the material budget maps will be recreated on the flight
+    /// and stored to the file. If the reference hash differs from one, read from the file, a warning will be produced,
+    /// and the new cache file will be generated.
+    void SetMaterialCacheFile(const TString& filename, size_t geoHash)
+    {
+      fBuilder.SetMaterialCacheFile(filename.Data(), geoHash);
+    }
+
     /// \brief  Initializes the instance
     /// \note   Is executed on the first call of MakeSetup function
     void Init();
diff --git a/sim/transport/steer/CbmSetup.cxx b/sim/transport/steer/CbmSetup.cxx
index 88ed27f365c69ead1bda4c567e05b5a0c4a6ca86..d8a3480f1dd4e88b96a8034370fa1d0cf4394d38 100644
--- a/sim/transport/steer/CbmSetup.cxx
+++ b/sim/transport/steer/CbmSetup.cxx
@@ -15,11 +15,8 @@
 #include "CbmFieldMapData.h"
 #include "CbmFieldMapSym2.h"
 #include "CbmFieldMapSym3.h"
-
 #include "FairModule.h"
 #include "FairRunSim.h"
-#include <Logger.h>
-
 #include "TFile.h"
 #include "TGeoMatrix.h"
 #include "TGeoNode.h"
@@ -27,8 +24,11 @@
 #include "TKey.h"
 #include "TSystem.h"
 
+#include <Logger.h>
+
 #include <iomanip>
 #include <sstream>
+#include <string>  // for std::hash<string_view>
 
 using std::string;
 using std::stringstream;
@@ -138,6 +138,24 @@ Bool_t CbmSetup::GetGeoTag(ECbmModuleId moduleId, TString& tag)
 // -------------------------------------------------------------------------
 
 
+// -----  Get a hash of the setup  -----------------------------------------
+size_t CbmSetup::GetHash()
+{
+  // TODO: make all getters constant (up to the CbmGeoSetupModule and co. classes)
+  std::string hashString{""};
+  auto& moduleMap = fProvider->GetSetup().GetModuleMap();
+  for (auto& entry : moduleMap) {
+    if (!hashString.empty()) {
+      hashString += ";";
+    }
+    hashString += entry.second.GetName() + ":" + entry.second.GetTag();
+  }
+  //LOG(info) << "CbmSetup::GetHash(): " << hashString;
+  return std::hash<std::string>{}(hashString);
+}
+// -------------------------------------------------------------------------
+
+
 // -----   Instance   ------------------------------------------------------
 CbmSetup* CbmSetup::Instance()
 {
diff --git a/sim/transport/steer/CbmSetup.h b/sim/transport/steer/CbmSetup.h
index 8ff24d4d008c957884e0132c314b2a081b4d2206..c31338c5a106681a6246fb84a9c515028283a22b 100644
--- a/sim/transport/steer/CbmSetup.h
+++ b/sim/transport/steer/CbmSetup.h
@@ -96,6 +96,15 @@ public:
   Bool_t GetGeoFileName(ECbmModuleId moduleId, TString& fileName);
 
 
+  /** Get a hash of the setup
+     ** @return  A 64-bit integer, representing the hash value
+     **
+     ** The hash is formed from a string of pairs "module name -- module tag", separated by semicolon. Only
+     ** active modules are considered.
+     **/
+  size_t GetHash();
+
+
   /** Get number of modules in the setup
      ** @value  Number of modules in setup
      **/