diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp
index 4eda855901616c72de9f6b3e86104f86a42556c7..7b57fa5bb4cce89672fde3454c45193c98c69547 100644
--- a/catalogue/Catalogue.hpp
+++ b/catalogue/Catalogue.hpp
@@ -159,13 +159,17 @@ public:
   /**
    * Creates a tape which is assumed to have logical block protection (LBP)
    * enabled.
+   *
+   * @param encryptionKey The optional identifier of the encrption key.  This
+   * optional parameter should either have a non-empty string value or no value
+   * at all.  Empty strings are prohibited.
    */
   virtual void createTape(
     const common::dataStructures::SecurityIdentity &cliIdentity,
     const std::string &vid,
     const std::string &logicalLibraryName,
     const std::string &tapePoolName,
-    const std::string &encryptionKey,
+    const optional<std::string> &encryptionKey,
     const uint64_t capacityInBytes,
     const bool disabled,
     const bool full,
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index 674023390343b177d3859ab06ad9a2c9e08cf421..1f74601d807c5ea23064631308cbfec58de07e72 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -1074,12 +1074,17 @@ void RdbmsCatalogue::createTape(
   const std::string &vid,
   const std::string &logicalLibraryName,
   const std::string &tapePoolName,
-  const std::string &encryptionKey,
+  const optional<std::string> &encryptionKey,
   const uint64_t capacityInBytes,
   const bool disabled,
   const bool full,
   const std::string &comment) {
   try {
+    if(encryptionKey && encryptionKey.value().empty()) {
+      throw(exception::Exception(std::string("The identifier of the encrption key for tape ") + vid + " has been set "
+        "to the empty string.  This optional value should either have a non-empty string value or no value at all"));
+    }
+
     auto conn = m_connPool.getConn();
     if(tapeExists(*conn, vid)) {
       throw exception::UserError(std::string("Cannot create tape ") + vid +
@@ -1134,7 +1139,7 @@ void RdbmsCatalogue::createTape(
     stmt->bindString(":VID", vid);
     stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
     stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
-    stmt->bindString(":ENCRYPTION_KEY", encryptionKey);
+    stmt->bindOptionalString(":ENCRYPTION_KEY", encryptionKey);
     stmt->bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
     stmt->bindUint64(":DATA_IN_BYTES", 0);
     stmt->bindUint64(":LAST_FSEQ", 0);
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index c80a6c9c200e163d8bf35f3458012beba20d2aa0..a293f8d86252afc3c55deb8224fa0c2ed0bf34e6 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -147,13 +147,17 @@ public:
   /**
    * Creates a tape which is assumed to have logical block protection (LBP)
    * enabled.
+   *
+   * @param encryptionKey The optional identifier of the encrption key.  This
+   * optional parameter should either have a non-empty string value or no value
+   * at all.  Empty strings are prohibited.
    */
   virtual void createTape(
     const common::dataStructures::SecurityIdentity &cliIdentity,
     const std::string &vid,
     const std::string &logicalLibraryName,
     const std::string &tapePoolName,
-    const std::string &encryptionKey,
+    const optional<std::string> &encryptionKey,
     const uint64_t capacityInBytes,
     const bool disabled,
     const bool full,
diff --git a/common/dataStructures/Tape.hpp b/common/dataStructures/Tape.hpp
index 95e9e245bc9cac835c7b4f02227114cd9389611f..d84497632017b5c80f02ee0d15f5efa63ce356fa 100644
--- a/common/dataStructures/Tape.hpp
+++ b/common/dataStructures/Tape.hpp
@@ -48,7 +48,15 @@ struct Tape {
   std::string tapePoolName;
   uint64_t capacityInBytes;
   uint64_t dataOnTapeInBytes;
+
+  /**
+   * The optional identifier of the encrption key.
+   *
+   * This optional should either have a non-empty string value or no value at
+   * all.  Empty strings are prohibited.
+   */
   optional<std::string> encryptionKey;
+
   bool lbp;
   bool full;
   bool disabled;
diff --git a/rdbms/OcciStmt.cpp b/rdbms/OcciStmt.cpp
index 56790d2420b7ec75a618e48497d3db8ca54cb256..222f7eb4e88ee17b8e8068fa43985caa679e82ab 100644
--- a/rdbms/OcciStmt.cpp
+++ b/rdbms/OcciStmt.cpp
@@ -102,8 +102,28 @@ void OcciStmt::bindUint64(const std::string &paramName, const uint64_t paramValu
 //------------------------------------------------------------------------------
 void OcciStmt::bindString(const std::string &paramName, const std::string &paramValue) {
   try {
+    bindOptionalString(paramName, paramValue);
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
+//------------------------------------------------------------------------------
+// bindOptionalString
+//------------------------------------------------------------------------------
+void OcciStmt::bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) {
+  try {
+    if(paramValue && paramValue.value().empty()) {
+      throw exception::Exception(std::string("Optional string parameter ") + paramName + " is an empty string. "
+        " An optional string parameter should either have a non-empty string value or no value at all."); 
+    }
+
     const unsigned paramIdx = m_paramNameToIdx.getIdx(paramName);
-    m_stmt->setString(paramIdx, paramValue);
+    if(paramValue) {
+      m_stmt->setString(paramIdx, paramValue.value());
+    } else {
+      m_stmt->setString(paramIdx, nullptr);
+    }
   } catch(exception::Exception &ex) {
     throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + getSql() + ": " +
       ex.getMessage().str());
diff --git a/rdbms/OcciStmt.hpp b/rdbms/OcciStmt.hpp
index acecf8d06cde9f8e7ffa589647556396ac914069..eebbfe9a2be41e6863b7a07041b879d4ebe3f808 100644
--- a/rdbms/OcciStmt.hpp
+++ b/rdbms/OcciStmt.hpp
@@ -86,14 +86,30 @@ public:
    */
   virtual void bindUint64(const std::string &paramName, const uint64_t paramValue) override;
 
-  /**
-   * Binds an SQL parameter.
+  /** 
+   * Binds an SQL parameter of type string.
+   *
+   * Please note that this method will throw an exception if the string
+   * parameter is empty.  If a null value is to be bound then the
+   * bindOptionalString() method should be used.
    *
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
-   */
+   */ 
   virtual void bindString(const std::string &paramName, const std::string &paramValue) override;
 
+  /** 
+   * Binds an SQL parameter of type optional-string.
+   *
+   * Please note that this method will throw an exception if the optional string
+   * parameter has the empty string as its value.  An optional string parameter
+   * should either have a non-empty string value or no value at all.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */ 
+  virtual void bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) override;
+
   /**
    *  Executes the statement and returns the result set.
    *
diff --git a/rdbms/SqliteStmt.cpp b/rdbms/SqliteStmt.cpp
index 50d6357560c7e9634f2060f29cb5a07abff9ba87..a7b5366eb55f8a530a772ee285b0e189e5803061 100644
--- a/rdbms/SqliteStmt.cpp
+++ b/rdbms/SqliteStmt.cpp
@@ -101,12 +101,36 @@ void SqliteStmt::bindUint64(const std::string &paramName, const uint64_t paramVa
 // bind
 //------------------------------------------------------------------------------
 void SqliteStmt::bindString(const std::string &paramName, const std::string &paramValue) {
-  const unsigned int paramIdx = m_paramNameToIdx.getIdx(paramName);
-  const int bindRc = paramValue.empty() ?
-    sqlite3_bind_text(m_stmt, paramIdx, nullptr, 0, SQLITE_TRANSIENT) :
-    sqlite3_bind_text(m_stmt, paramIdx, paramValue.c_str(), -1, SQLITE_TRANSIENT);
-  if(SQLITE_OK != bindRc) {
-    throw exception::Exception(std::string(__FUNCTION__) + "failed for SQL statement " + getSql());
+  try {
+    bindOptionalString(paramName, paramValue);
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + getSql() + ": " +
+      ex.getMessage().str()); 
+  }
+}
+
+//------------------------------------------------------------------------------
+// bindOptionalString
+//------------------------------------------------------------------------------
+void SqliteStmt::bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) {
+  try {
+    if(paramValue && paramValue.value().empty()) {
+      throw exception::Exception(std::string("Optional string parameter ") + paramName + " is an empty string. "
+        " An optional string parameter should either have a non-empty string value or no value at all.");
+    }
+    const unsigned int paramIdx = m_paramNameToIdx.getIdx(paramName);
+    int bindRc = 0;
+    if(paramValue) {
+      bindRc = sqlite3_bind_text(m_stmt, paramIdx, paramValue.value().c_str(), -1, SQLITE_TRANSIENT);
+    } else {    
+      bindRc = sqlite3_bind_text(m_stmt, paramIdx, nullptr, 0, SQLITE_TRANSIENT);
+    }
+    if(SQLITE_OK != bindRc) {
+      throw exception::Exception(getSql());
+    }
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + getSql() + ": " +
+      ex.getMessage().str()); 
   }
 }
 
diff --git a/rdbms/SqliteStmt.hpp b/rdbms/SqliteStmt.hpp
index dc5edec3e55fb4bef577b79a143776388e20adbf..717c5274cc3295b88116b74835981c1281b60051 100644
--- a/rdbms/SqliteStmt.hpp
+++ b/rdbms/SqliteStmt.hpp
@@ -84,13 +84,29 @@ public:
   virtual void bindUint64(const std::string &paramName, const uint64_t paramValue) override;
 
   /** 
-   * Binds an SQL parameter.
+   * Binds an SQL parameter of type string.
+   *
+   * Please note that this method will throw an exception if the string
+   * parameter is empty.  If a null value is to be bound then the
+   * bindOptionalString() method should be used.
    *
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
    */ 
   virtual void bindString(const std::string &paramName, const std::string &paramValue) override;
 
+  /** 
+   * Binds an SQL parameter of type optional-string.
+   *
+   * Please note that this method will throw an exception if the optional string
+   * parameter has the empty string as its value.  An optional string parameter
+   * should either have a non-empty string value or no value at all.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */ 
+  virtual void bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) override;
+
   /**
    * Executes the statement and returns the result set.
    *
diff --git a/rdbms/Stmt.hpp b/rdbms/Stmt.hpp
index efc5c57ad10f28ed0766a000901efdd197ada55b..b480b340b02b87191a4af30f64653fa97989936b 100644
--- a/rdbms/Stmt.hpp
+++ b/rdbms/Stmt.hpp
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include "common/optional.hpp"
 #include "rdbms/Rset.hpp"
 
 #include <memory>
@@ -59,13 +60,29 @@ public:
   virtual void bindUint64(const std::string &paramName, const uint64_t paramValue) = 0;
 
   /** 
-   * Binds an SQL parameter.
+   * Binds an SQL parameter of type string.
+   *
+   * Please note that this method will throw an exception if the string
+   * parameter is empty.  If a null value is to be bound then the
+   * bindOptionalString() method should be used.
    *
    * @param paramName The name of the parameter.
    * @param paramValue The value to be bound.
    */ 
   virtual void bindString(const std::string &paramName, const std::string &paramValue) = 0;
 
+  /** 
+   * Binds an SQL parameter of type optional-string.
+   *
+   * Please note that this method will throw an exception if the optional string
+   * parameter has the empty string as its value.  An optional string parameter
+   * should either have a non-empty string value or no value at all.
+   *
+   * @param paramName The name of the parameter.
+   * @param paramValue The value to be bound.
+   */ 
+  virtual void bindOptionalString(const std::string &paramName, const optional<std::string> &paramValue) = 0;
+
   /**
    *  Executes the statement and returns the result set.
    *
diff --git a/scheduler/SchedulerTest.cpp b/scheduler/SchedulerTest.cpp
index cfcdd5c2ddd2aba7558932ac02dfb7008a6e1174..fbb9f56e747cbd185bf3c56d49739b2199041248 100644
--- a/scheduler/SchedulerTest.cpp
+++ b/scheduler/SchedulerTest.cpp
@@ -391,8 +391,8 @@ TEST_P(SchedulerTest, archive_and_retrieve_new_file) {
   const std::string tapeComment = "Tape comment";
   bool notDisabled = false;
   bool notFull = false;
-  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName,
-    s_tapePoolName, "", capacityInBytes, notDisabled, notFull, tapeComment);
+  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName, s_tapePoolName, nullopt, capacityInBytes,
+    notDisabled, notFull, tapeComment);
 
   {
     // Emulate a tape server by asking for a mount and then a file (and succeed
@@ -528,8 +528,8 @@ TEST_P(SchedulerTest, retry_archive_until_max_reached) {
   const std::string tapeComment = "Tape comment";
   bool notDisabled = false;
   bool notFull = false;
-  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName,
-    s_tapePoolName, "", capacityInBytes, notDisabled, notFull, tapeComment);
+  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName, s_tapePoolName, nullopt, capacityInBytes, notDisabled,
+    notFull, tapeComment);
   
   {
     // Emulate a tape server by asking for a mount and then a file
diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
index 174a8d3347123a784f3598961cd6a9aaceea8292..66706c8cf3f0f0bfd9b3247399340e70867bd64b 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
+++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
@@ -352,8 +352,8 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayRecall) {
   const std::string tapeComment = "Tape comment";
   bool notDisabled = false;
   bool notFull = false;
-  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName,
-    s_tapePoolName, "", capacityInBytes, notDisabled, notFull, tapeComment);
+  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName, s_tapePoolName, cta::nullopt, capacityInBytes,
+    notDisabled, notFull, tapeComment);
   
   // 6) Prepare files for reading by writing them to the mock system
   {