diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index 2d67deaac567ab59dcca0499786c60858a697c98..2e301dac009f5d88e9212aa00cf9e07cd2e04413 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -440,7 +440,7 @@ private:
     void dumpBucket(const Bucket& b, std::ostream& out) const;
 
     // Nodes
-    std::shared_ptr<Node> newNode(const std::shared_ptr<Node>& node, int confirm);
+    void onNewNode(const std::shared_ptr<Node>& node, int confirm);
     std::shared_ptr<Node> findNode(const InfoHash& id, sa_family_t af);
     const std::shared_ptr<Node> findNode(const InfoHash& id, sa_family_t af) const;
     bool trySearchInsert(const std::shared_ptr<Node>& node);
diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h
index 5986b9a566c0e82b8c56930909e79a3f7fb0e833..3a37354ee49707c76faeb80cb702ad7ac5000fba 100644
--- a/include/opendht/network_engine.h
+++ b/include/opendht/network_engine.h
@@ -187,7 +187,7 @@ private:
      * @param saddr_len (type: socklen_t) lenght of the sockaddr struct.
      * @param confirm (type: int) 1 if the node sent a message, 2 if it sent us a reply.
      */
-    std::function<std::shared_ptr<Node>(const std::shared_ptr<Node>&, int)> onNewNode;
+    std::function<void(const std::shared_ptr<Node>&, int)> onNewNode;
     /**
      * @brief when an addres is reported from a distant node.
      *
diff --git a/src/dht.cpp b/src/dht.cpp
index ce4e24f3d0a11bdc8558563d0dec915e7fb3a0a9..2b4a156565f6d5cc31b5c3b59a3459009fc40559 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -455,19 +455,19 @@ Dht::reportedAddr(const sockaddr *sa, socklen_t sa_len)
 
 /* We just learnt about a node, not necessarily a new one.  Confirm is 1 if
    the node sent a message, 2 if it sent us a reply. */
-std::shared_ptr<Node>
-Dht::newNode(const std::shared_ptr<Node>& node, int confirm)
+void
+Dht::onNewNode(const std::shared_ptr<Node>& node, int confirm)
 {
     auto& list = node->getFamily() == AF_INET ? buckets : buckets6;
     auto b = list.findBucket(node->id);
     if (b == list.end())
-        return {};
+        return;
 
     for (auto& n : b->nodes) {
         if (n == node) {
             if (confirm)
                 trySearchInsert(node);
-            return n;
+            return;
         }
     }
 
@@ -490,7 +490,7 @@ Dht::newNode(const std::shared_ptr<Node>& node, int confirm)
         if (not n->isExpired())
             continue;
         n = node;
-        return n;
+        return;
     }
 
     if (b->nodes.size() >= TARGET_NODES) {
@@ -515,7 +515,8 @@ Dht::newNode(const std::shared_ptr<Node>& node, int confirm)
             DHT_LOG.DEBUG("Splitting from depth %u", list.depth(b));
             sendCachedPing(*b);
             list.split(b);
-            return newNode(node, 0);
+            onNewNode(node, 0);
+            return;
         }
 
         /* No space for this node.  Cache it away for later. */
@@ -525,8 +526,6 @@ Dht::newNode(const std::shared_ptr<Node>& node, int confirm)
         /* Create a new node. */
         b->nodes.emplace_front(node);
     }
-
-    return node;
 }
 
 /* Called periodically to purge known-bad nodes.  Note that we're very
@@ -882,7 +881,7 @@ Dht::searchStep(std::shared_ptr<Search> sr)
                         g.done_cb(false, {});
                 }
             }
-            {
+            if (not sr->nodes.empty()) {
                 std::vector<DoneCallback> a_cbs;
                 a_cbs.reserve(sr->announce.size());
                 for (const auto& a : sr->announce)
@@ -2049,7 +2048,7 @@ Dht::Dht(int s, int s6, Config config)
  : myid(config.node_id), is_bootstrap(config.is_bootstrap), store(),
     network_engine(myid, s, s6, DHT_LOG, scheduler,
             std::bind(&Dht::onError, this, _1, _2),
-            std::bind(&Dht::newNode, this, _1, _2),
+            std::bind(&Dht::onNewNode, this, _1, _2),
             std::bind(&Dht::onReportedAddr, this, _1, _2, _3),
             std::bind(&Dht::onPing, this, _1),
             std::bind(&Dht::onFindNode, this, _1, _2, _3),