diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua
index 20bd48d0de3f866f261cc5d4013d58559f8fff69..7d06d2003f9208aa159c0cde6724210f692d2a0b 100644
--- a/daemon/lua/kres-gen.lua
+++ b/daemon/lua/kres-gen.lua
@@ -322,7 +322,7 @@ _Bool kr_dnssec_key_ksk(const uint8_t *);
 _Bool kr_dnssec_key_revoked(const uint8_t *);
 int kr_dnssec_key_tag(uint16_t, const uint8_t *, size_t);
 int kr_dnssec_key_match(const uint8_t *, size_t, const uint8_t *, size_t);
-int kr_cache_closest_apex(struct kr_cache *, const knot_dname_t *, _Bool);
+int kr_cache_closest_apex(struct kr_cache *, const knot_dname_t *, _Bool, knot_dname_t **);
 int kr_cache_insert_rr(struct kr_cache *, const knot_rrset_t *, const knot_rrset_t *, uint8_t, uint32_t);
 int kr_cache_remove(struct kr_cache *, const knot_dname_t *, uint16_t);
 int kr_cache_remove_subtree(struct kr_cache *, const knot_dname_t *, _Bool, int);
diff --git a/daemon/lua/sandbox.lua b/daemon/lua/sandbox.lua
index e76bc54a4d5481ac6c6821cc03d01971d955bd27..af5b10dc4281a0a32a2ab251f85258b3cfa044b4 100644
--- a/daemon/lua/sandbox.lua
+++ b/daemon/lua/sandbox.lua
@@ -173,11 +173,16 @@ cache.clear = function (name, exact_name, rr_type, maxcount, callback)
 	-- we assume they are advanced enough not to need the check.
 	-- The point is to avoid repeating the check in each callback iteration.
 	if callback == nil then
-		local apex_dist = ffi.C.kr_cache_closest_apex(cach, dname, false)
-		if apex_dist < 0 then error(ffi.string(ffi.C.knot_strerror(apex_dist))) end
-		if apex_dist > 0 then
-			errors.not_apex = 'Negative proofs not cleared, call clear again '
-							.. tostring(apex_dist) .. ' label(s) higher.'
+		local names = ffi.new('knot_dname_t *[1]')  -- C: dname **names
+		local ret = ffi.C.kr_cache_closest_apex(cach, dname, false, names)
+		if ret < 0 then
+			error(ffi.string(ffi.C.knot_strerror(ret))) end
+		ffi.gc(names[0], ffi.C.free)
+		local apex = kres.dname2str(names[0])
+		if apex ~= name then
+			errors.not_apex = 'to clear proofs of non-existence call '
+				.. 'cache.clear(\'' .. tostring(apex) ..'\')'
+			errors.subtree = apex
 		end
 	end
 
@@ -340,7 +345,7 @@ function table_print (tt, indent, done)
 			if c >= 0x20 and c < 0x7f then table.insert(bytes, string.char(c))
 			else                           table.insert(bytes, '\\'..tostring(c))
 			end
-			if i > 70 then table.insert(bytes, '...') break end
+			if i > 80 then table.insert(bytes, '...') break end
 		end
 		return table.concat(bytes)
 	end
diff --git a/lib/cache/api.h b/lib/cache/api.h
index 9034fa182e4dd232d6ca36b669c092a1151cf945..84d0f07dbe0a0cbc5656f16f42ee09e59b590a84 100644
--- a/lib/cache/api.h
+++ b/lib/cache/api.h
@@ -179,7 +179,8 @@ int kr_cache_remove_subtree(struct kr_cache *cache, const knot_dname_t *name,
  * @note timestamp is found by a syscall, and stale-serving is not considered
  */
 KR_EXPORT
-int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS);
+int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS,
+			  knot_dname_t **apex);
 
 /**
  * Unpack dname and type from db key
diff --git a/lib/cache/peek.c b/lib/cache/peek.c
index cdb5c81c054ba2f92b090c861c3c4a55923244e5..1c8749776f0fc9bf01256621be5d58be0eb56073 100644
--- a/lib/cache/peek.c
+++ b/lib/cache/peek.c
@@ -553,20 +553,26 @@ static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clenc
 	return kr_ok();
 }
 
-int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS)
+int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS,
+			  knot_dname_t ** apex)
 {
-	if (!cache || !name) {
+	if (!cache || !cache->db || !name || !apex || *apex) {
 		assert(!EINVAL);
 		return kr_error(EINVAL);
 	}
 	struct key k_storage, *k = &k_storage;
 	int ret = kr_dname_lf(k->buf, name, false);
-	if (ret) return kr_error(ret);
+	if (ret)
+		return kr_error(ret);
 	entry_list_t el_;
 	k->zname = name;
 	ret = closest_NS(cache, k, el_, NULL, true, is_DS);
-	if (ret && ret != -abs(ENOENT)) return ret;
-	return knot_dname_labels(name, NULL) - knot_dname_labels(k->zname, NULL);
+	if (ret && ret != -abs(ENOENT))
+		return ret;
+	*apex = knot_dname_copy(k->zname, NULL);
+	if (!*apex)
+		return kr_error(ENOMEM);
+	return kr_ok();
 }
 
 /** \internal for closest_NS.  Check suitability of a single entry, setting k->type if OK.