diff --git a/src/dht.cpp b/src/dht.cpp
index 84495267e022a52ee7d4e681634a129c3df8fbe1..bcdfb69ba98699d5eb44db6eaef2da875e2c6343 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -870,7 +870,7 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
         throw DhtException("Can't create search");
     if (logger_)
         logger_->w(id, "[search %s IPv%c] listen", id.to_c_str(), (af == AF_INET) ? '4' : '6');
-    return sr->listen(cb, f, q, scheduler);
+    return sr->listen(cb, std::move(f), q, scheduler);
 }
 
 size_t
@@ -889,7 +889,7 @@ Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where)
     });
 
     auto query = std::make_shared<Query>(Select{}, std::move(where));
-    auto filter = f.chain(query->where.getFilter());
+    auto filter = Value::Filter::chain(std::move(f), query->where.getFilter());
     auto st = store.find(id);
     if (st == store.end() && store.size() < max_store_keys)
         st = store.emplace(id, scheduler.time() + MAX_STORAGE_MAINTENANCE_EXPIRE_TIME).first;
diff --git a/src/op_cache.cpp b/src/op_cache.cpp
index fa66583c97c1da08e21126cd62b44a07f4ad3ea7..a918e5c01d47443b77edaaa0477c95a413a12725 100644
--- a/src/op_cache.cpp
+++ b/src/op_cache.cpp
@@ -175,7 +175,7 @@ SearchCache::getOp(const Sp<Query>& q) const
 }
 
 size_t
-SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen)
+SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, Value::Filter&& filter, const OnListen& onListen)
 {
     // find exact match
     auto op = getOp(q);
@@ -192,7 +192,7 @@ SearchCache::listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value
     auto token = nextToken_++;
     if (nextToken_ == 0)
         nextToken_++;
-    return op->second->addListener(token, get_cb, q, filter) ? token : 0;
+    return op->second->addListener(token, get_cb, q, std::move(filter)) ? token : 0;
 }
 
 bool
diff --git a/src/op_cache.h b/src/op_cache.h
index a32751fea7faf69464079e4faac43548c0012e89..ba7c12972edba49693155c07f58b07e9b26a79f0 100644
--- a/src/op_cache.h
+++ b/src/op_cache.h
@@ -107,12 +107,12 @@ public:
     void onValuesAdded(const std::vector<Sp<Value>>& vals);
     void onValuesExpired(const std::vector<Sp<Value>>& vals);
 
-    bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, const Value::Filter& filter) {
+    bool addListener(size_t token, const ValueCallback& cb, const Sp<Query>& q, Value::Filter&& filter) {
         auto cached = cache.get(filter);
         if (not cached.empty() and not cb(cached, false)) {
             return false;
         }
-        listeners.emplace(token, LocalListener{q, filter, cb});
+        listeners.emplace(token, LocalListener{q, std::move(filter), cb});
         return true;
     }
 
@@ -167,7 +167,7 @@ public:
     SearchCache(SearchCache&&) = default;
 
     using OnListen = std::function<size_t(Sp<Query>, ValueCallback, SyncCallback)>;
-    size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, const Value::Filter& filter, const OnListen& onListen);
+    size_t listen(const ValueCallback& get_cb, const Sp<Query>& q, Value::Filter&& filter, const OnListen& onListen);
 
     bool cancelListen(size_t gtoken, const time_point& now);
     void cancelAll(const std::function<void(size_t)>& onCancel);
diff --git a/src/search.h b/src/search.h
index 5ec9160cc92b4e1297a3344fbc9254722298f909..717bf8ac04d9652b9e8a024a201c88c69b848e39 100644
--- a/src/search.h
+++ b/src/search.h
@@ -547,9 +547,9 @@ struct Dht::Search {
         }
     }
 
-    size_t listen(const ValueCallback& cb, const Value::Filter& f, const Sp<Query>& q, Scheduler& scheduler) {
+    size_t listen(const ValueCallback& cb, Value::Filter&& f, const Sp<Query>& q, Scheduler& scheduler) {
         //DHT_LOG.e(id, "[search %s IPv%c] listen", id.toString().c_str(), (af == AF_INET) ? '4' : '6');
-        return cache.listen(cb, q, f, [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
+        return cache.listen(cb, q, std::move(f), [&](const Sp<Query>& q, ValueCallback vcb, SyncCallback scb){
             done = false;
             auto token = ++listener_token;
             listeners.emplace(token, SearchListener{q, vcb, scb});