diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp
index 05b7c31fa3ea2f2c7d937d524187453cd4a70851..33d26290836f1c06d83ba8a13905426cb564a97c 100644
--- a/catalogue/Catalogue.hpp
+++ b/catalogue/Catalogue.hpp
@@ -554,6 +554,14 @@ public:
    */
   virtual bool tapePoolExists(const std::string &tapePoolName) const = 0;
 
+  /**
+   * Returns true if the specified tape exists.
+   *
+   * @param vid The volume identifier of the tape.
+   * @return True if the tape exists.
+   */
+  virtual bool tapeExists(const std::string &vid) const = 0;
+
 }; // class Catalogue
 
 } // namespace catalogue
diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp
index ef44e2dac8472abe0ed666ef200f8bc06aae0ceb..47dd923b8df670bcf6d8beaef617f4edc2ee84e4 100644
--- a/catalogue/CatalogueTest.cpp
+++ b/catalogue/CatalogueTest.cpp
@@ -1640,6 +1640,9 @@ TEST_P(cta_catalogue_CatalogueTest, createTape) {
   ASSERT_TRUE(m_catalogue->getTapes().empty());
 
   const std::string vid = "vid";
+
+  ASSERT_FALSE(m_catalogue->tapeExists(vid));
+
   const std::string logicalLibraryName = "logical_library_name";
   const std::string tapePoolName = "tape_pool_name";
   const std::string encryptionKey = "encryption_key";
@@ -1654,6 +1657,8 @@ TEST_P(cta_catalogue_CatalogueTest, createTape) {
   m_catalogue->createTape(m_admin, vid, logicalLibraryName, tapePoolName, encryptionKey, capacityInBytes, disabledValue,
     fullValue, comment);
 
+  ASSERT_TRUE(m_catalogue->tapeExists(vid));
+
   const std::list<common::dataStructures::Tape> tapes =
     m_catalogue->getTapes();
 
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index e9798699e73d45471a01da45454131982b87106f..4977233388a2f311ab6819e1309ad8d3e5994810 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -1623,6 +1623,18 @@ void RdbmsCatalogue::createTape(
   }
 }
 
+//------------------------------------------------------------------------------
+// tapeExists
+//------------------------------------------------------------------------------
+bool RdbmsCatalogue::tapeExists(const std::string &vid) const {
+  try {
+    auto conn = m_connPool.getConn();
+    return tapeExists(conn, vid);
+  } catch (exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
 //------------------------------------------------------------------------------
 // tapeExists
 //------------------------------------------------------------------------------
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index 5895926e9112f170c4433458b2297bbc0ed2a3f6..4c093af77247b738097157093138d5ecd3f4b8cf 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -659,6 +659,14 @@ protected:
   bool archiveRouteExists(rdbms::PooledConn &conn, const std::string &diskInstanceName, const std::string &storageClassName,
     const uint64_t copyNb) const;
 
+  /**
+   * Returns true if the specified tape exists.
+   *
+   * @param vid The volume identifier of the tape.
+   * @return True if the tape exists.
+   */
+  bool tapeExists(const std::string &vid) const override;
+
   /**
    * Returns true if the specified tape exists.
    *