diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 569f0335c6371a324f7209eeab09e1883e0a3bcd..0699e14b28ae6e4b44ff495695c843ffa2e8d01f 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -196,6 +196,14 @@ public:
   [[nodiscard]] virtual auto size() const noexcept -> int = 0;
   [[nodiscard]] virtual auto at(const int index) const -> const Entity & = 0;
   [[nodiscard]] virtual auto mutable_at(int index) const -> Entity * = 0;
+  /**
+   * Return the Entity at the given index.
+   *
+   * This method releases the entity from the underlying collection and thus
+   * leaves the ResultSet in a corrupted state.
+   *
+   * This method can be called only once for each index.
+   */
   [[nodiscard]] virtual auto release_at(int index) -> Entity * = 0;
   auto begin() const -> iterator;
   auto end() const -> iterator;
@@ -217,6 +225,11 @@ private:
 
 class AbstractMultiResultSet : public ResultSet {
 public:
+  /**
+   * Copy Constructor.
+   *
+   * Copies the underlying collection of entities.
+   */
   inline AbstractMultiResultSet(const AbstractMultiResultSet &original) {
     for (const Entity &entity : original) {
       this->items.push_back(std::make_unique<Entity>(entity));
@@ -232,9 +245,20 @@ public:
   [[nodiscard]] inline auto mutable_at(int index) const -> Entity * override {
     return this->items.at(index).get();
   }
+  /**
+   * Return the Entity at the given index.
+   *
+   * This method releases the entity from the underlying collection and thus
+   * leaves the ResultSet in a corrupted state.
+   *
+   * This method can be called only once for each index.
+   */
   [[nodiscard]] inline auto release_at(int index) -> Entity * override {
     return this->items.at(index).release();
   }
+  /**
+   * Remove all entities from this result set.
+   */
   inline auto clear() noexcept -> void { this->items.clear(); }
 
 protected:
@@ -375,14 +399,38 @@ public:
    */
   [[nodiscard]] inline auto GetStatus() const noexcept -> TransactionStatus { return this->status; }
 
+  /**
+   * Return the ResultSet of this transaction.
+   *
+   * Note: If this method is called before the transaction has terminated
+   * (GetStatus().GetCode() < 0) this method has undefined behavior.
+   *
+   * Instead, do Execute() or WaitForIt() and only call this method afterwards.
+   */
   [[nodiscard]] inline auto GetResultSet() const noexcept -> const ResultSet & {
     if (!this->result_set) {
-      // TODO(tf) Discuss. This condition implies a programming error. Should we handle it?
+      CAOSDB_LOG_ERROR(logger_name)
+        << "GetResultSet was called before the transaction has terminated. This is a programming "
+           "error of the code which uses the transaction.";
+      // TODO(tf) This is a really bad SegFault factory. When the transaction
+      // terminates and the result_set is being overriden, the unique_ptr
+      // created here will be deleted and any client of the return ResultSet
+      // will have a SegFault.
       this->result_set = std::make_unique<MultiResultSet>(std::vector<std::unique_ptr<Entity>>());
     }
     return *(this->result_set.get());
   }
 
+  /**
+   * Return the ResultSet of this transaction.
+   *
+   * This method releases the ResultSet from the transaction leaving it in a
+   * currupted state.
+   *
+   * This method can be called only once and only after the transaction has terminated.
+   *
+   * Otherwise, this method has undefined behavior.
+   */
   [[nodiscard]] inline auto ReleaseResultSet() noexcept -> const ResultSet * {
     this->status = TransactionStatus::SPOILED();
     return this->result_set.release();