diff --git a/daemon/worker.c b/daemon/worker.c
index 5dd994e900bd6336aebec3a624ac981294f4c2b8..129335fd1024031b33b7d690dd2e3a03e7fbb838 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -1664,12 +1664,13 @@ static int qr_task_step(struct qr_task *task,
 			if (task->iter_count > KR_ITER_LIMIT) {
 				char *msg = "cancelling query due to exceeded iteration count limit";
 				VERBOSE_MSG(last, "%s of %d\n", msg, KR_ITER_LIMIT);
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, msg);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER,
+					"OGHD: exceeded iteration count limit");
 			}
 			if (task->timeouts >= KR_TIMEOUT_LIMIT) {
 				char *msg = "cancelling query due to exceeded timeout retries limit";
 				VERBOSE_MSG(last, "%s of %d\n", msg, KR_TIMEOUT_LIMIT);
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_NREACH_AUTH, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_NREACH_AUTH, "QLPL");
 			}
 
 			return qr_task_finalize(task, KR_STATE_FAIL);
diff --git a/lib/cache/api.c b/lib/cache/api.c
index 6421c66eb2074df3117e3cd24ef075262391e389..6a572b034fd147ed7837c9e7c71faca4abd9feff 100644
--- a/lib/cache/api.c
+++ b/lib/cache/api.c
@@ -241,7 +241,7 @@ int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
 			VERBOSE_MSG(qry, "responding with stale answer\n");
 			/* LATER: Perhaps we could use a more specific Stale
 			 * NXDOMAIN Answer code for applicable responses. */
-			kr_request_set_extended_error(qry->request, KNOT_EDNS_EDE_STALE, NULL);
+			kr_request_set_extended_error(qry->request, KNOT_EDNS_EDE_STALE, "6Q6X");
 			return res_stale;
 		}
 	}
diff --git a/lib/layer/validate.c b/lib/layer/validate.c
index aa1715e1b7b8d24dc83bf9e79a646e163ad38a35..7f372d4ba9be3986352f5d01aec3c2d895e28c04 100644
--- a/lib/layer/validate.c
+++ b/lib/layer/validate.c
@@ -236,17 +236,17 @@ static int validate_section(kr_rrset_validation_ctx_t *vctx, struct kr_query *qr
 			/* no RRSIGs found */
 			kr_rank_set(&entry->rank, KR_RANK_MISSING);
 			vctx->err_cnt += 1;
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_RRSIG_MISS, NULL);  // TODO double-check EDE
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_RRSIG_MISS, "JZAJ");
 			log_bogus_rrsig(vctx, rr, "no valid RRSIGs found");
 		} else {
 			kr_rank_set(&entry->rank, KR_RANK_BOGUS);
 			vctx->err_cnt += 1;
 			if (vctx->rrs_counters.expired > 0)
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_EXPIRED, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_EXPIRED, "YFJ2");
 			else if (vctx->rrs_counters.notyet > 0)
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_NOTYET, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_NOTYET, "UBBS");
 			else
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "I74V");
 			log_bogus_rrsig(vctx, rr, "bogus signatures");
 		}
 	}
@@ -365,7 +365,7 @@ static int validate_keyset(struct kr_request *req, knot_pkt_t *answer, bool has_
 			}
 		}
 		if (sig_index < 0) {
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_RRSIG_MISS, NULL);
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_RRSIG_MISS, "EZDC");
 			return kr_error(ENOENT);
 		}
 		const knot_rdataset_t *sig_rds = &req->answ_selected.at[sig_index]->rr->rrs;
@@ -394,11 +394,11 @@ static int validate_keyset(struct kr_request *req, knot_pkt_t *answer, bool has_
 			knot_rrset_free(qry->zone_cut.key, qry->zone_cut.pool);
 			qry->zone_cut.key = NULL;
 			if (vctx.rrs_counters.expired > 0)
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_EXPIRED, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_EXPIRED, "6GJV");
 			else if (vctx.rrs_counters.notyet > 0)
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_NOTYET, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_SIG_NOTYET, "4DJQ");
 			else
-				kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+				kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "EXRU");
 			return ret;
 		}
 
@@ -567,7 +567,7 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_
 			}
 		} else if (ret != 0) {
 			VERBOSE_MSG(qry, "<= bogus proof of DS non-existence\n");
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "Z4I6");
 			qry->flags.DNSSEC_BOGUS = true;
 		} else if (proved_name[0] != '\0') { /* don't go to insecure for . DS */
 			qry->flags.DNSSEC_NODS = true;
@@ -712,7 +712,8 @@ static int check_validation_result(kr_layer_t *ctx, const knot_pkt_t *pkt, ranke
 	if (!kr_rank_test(invalid_entry->rank, KR_RANK_SECURE) &&
 	    (++(invalid_entry->revalidation_cnt) > MAX_REVALIDATION_CNT)) {
 		VERBOSE_MSG(qry, "<= continuous revalidation, fails\n");
-		kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "continuous revalidation, fails");
+		kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER,
+			"4T4L: continuous revalidation");
 		qry->flags.DNSSEC_BOGUS = true;
 		return KR_STATE_FAIL;
 	}
@@ -736,7 +737,7 @@ static int check_validation_result(kr_layer_t *ctx, const knot_pkt_t *pkt, ranke
 	} else if (kr_rank_test(invalid_entry->rank, KR_RANK_MISSING)) {
 		ret = rrsig_not_found(ctx, pkt, rr);
 	} else if (!kr_rank_test(invalid_entry->rank, KR_RANK_SECURE)) {
-		kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+		kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "NXJA");
 		qry->flags.DNSSEC_BOGUS = true;
 		ret = KR_STATE_FAIL;
 	}
@@ -1074,7 +1075,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 	bool use_signatures = (knot_pkt_qtype(pkt) != KNOT_RRTYPE_RRSIG);
 	if (!(qry->flags.CACHED) && !knot_pkt_has_dnssec(pkt) && !use_signatures) {
 		VERBOSE_MSG(qry, "<= got insecure response\n");
-		kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+		kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "MISQ");
 		qry->flags.DNSSEC_BOGUS = true;
 		return KR_STATE_FAIL;
 	}
@@ -1090,7 +1091,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 		 * but iterator has not selected any records. */
 		if (!check_empty_answer(ctx, pkt)) {
 			VERBOSE_MSG(qry, "<= no useful RR in authoritative answer\n");
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "MJX6");
 			qry->flags.DNSSEC_BOGUS = true;
 			return KR_STATE_FAIL;
 		}
@@ -1112,7 +1113,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 		if (ds && !kr_ds_algo_support(ds)) {
 			VERBOSE_MSG(qry, ">< all DS entries use unsupported algorithm pairs, going insecure\n");
 			/* ^ the message is a bit imprecise to avoid being too verbose */
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "unsupported digest/key");
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "LSLC: unsupported digest/key");
 			qry->flags.DNSSEC_WANT = false;
 			qry->flags.DNSSEC_INSECURE = true;
 			rank_records(qry, true, KR_RANK_INSECURE, qry->zone_cut.name);
@@ -1143,7 +1144,8 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 			/* something exceptional - no DNS key, empty pointers etc
 			 * normally it shouldn't happen */
 			VERBOSE_MSG(qry, "<= couldn't validate RRSIGs\n");
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER, "couldn't validate RRSIGs");
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_OTHER,
+				"O4TP: couldn't validate RRSIGs");
 			qry->flags.DNSSEC_BOGUS = true;
 			return KR_STATE_FAIL;
 		}
@@ -1182,7 +1184,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 			VERBOSE_MSG(qry, "<= can't prove NXDOMAIN due to optout, going insecure\n");
 		} else if (ret != 0) {
 			VERBOSE_MSG(qry, "<= bad NXDOMAIN proof\n");
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_NSEC_MISS, NULL);
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_NSEC_MISS, "3WKM");
 			qry->flags.DNSSEC_BOGUS = true;
 			return KR_STATE_FAIL;
 		}
@@ -1214,7 +1216,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 					 * parent queries as insecure */
 				} else {
 					VERBOSE_MSG(qry, "<= bad NODATA proof\n");
-					kr_request_set_extended_error(req, KNOT_EDNS_EDE_NSEC_MISS, NULL);
+					kr_request_set_extended_error(req, KNOT_EDNS_EDE_NSEC_MISS, "AHXI");
 					qry->flags.DNSSEC_BOGUS = true;
 					return KR_STATE_FAIL;
 				}
@@ -1229,7 +1231,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
 	if (ret == DNSSEC_NOT_FOUND && qry->stype != KNOT_RRTYPE_DS) {
 		if (ctx->state == KR_STATE_YIELD) {
 			VERBOSE_MSG(qry, "<= can't validate referral\n");
-			kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, NULL);
+			kr_request_set_extended_error(req, KNOT_EDNS_EDE_BOGUS, "XLE4");
 			qry->flags.DNSSEC_BOGUS = true;
 			return KR_STATE_FAIL;
 		} else {
diff --git a/lib/resolve.h b/lib/resolve.h
index d83c083d2bc249238beff260522161b55d0d52e1..7d6cdd19bfb6fb64809903f73bddca4bdd609304 100644
--- a/lib/resolve.h
+++ b/lib/resolve.h
@@ -382,6 +382,11 @@ knot_mm_t *kr_resolve_pool(struct kr_request *request);
  * allocated either statically, or on the request's mempool. To clear any
  * error, call it with KNOT_EDNS_EDE_NONE and NULL as extra_text.
  *
+ * To facilitate debugging, we include a unique base32 identifier at the start
+ * of the extra_text field for every call of this function. To generate such an
+ * identifier, you can use the command:
+ * $ base32 /dev/random | head -c 4
+ *
  * @param  request     request state
  * @param  info_code   extended DNS error code
  * @param  extra_text  optional string with additional information
@@ -392,7 +397,7 @@ int kr_request_set_extended_error(struct kr_request *request, int info_code, con
 
 static inline void kr_query_inform_timeout(struct kr_request *req, const struct kr_query *qry)
 {
-	kr_request_set_extended_error(req, KNOT_EDNS_EDE_NREACH_AUTH, NULL);
+	kr_request_set_extended_error(req, KNOT_EDNS_EDE_NREACH_AUTH, "RRPF");
 
 	unsigned ind = 0;
 	for (const struct kr_query *q = qry; q; q = q->parent)
diff --git a/modules/dns64/dns64.lua b/modules/dns64/dns64.lua
index 7d839247aadf3a442aeae66693a4c44b27fa6d5c..0f81ed2141ae640d1df5a454688206eaf8f3761a 100644
--- a/modules/dns64/dns64.lua
+++ b/modules/dns64/dns64.lua
@@ -1,6 +1,5 @@
 -- SPDX-License-Identifier: GPL-3.0-or-later
 -- Module interface
-local kluautil = require('kluautil')
 local kres = require('kres')
 local ffi = require('ffi')
 local C = ffi.C
@@ -153,8 +152,7 @@ function M.layer.consume(state, req, pkt)
 		end
 	end
 	ffi.C.kr_ranked_rrarray_finalize(req.answ_selected, qry.uid, req.pool)
-	local msg = kluautil.kr_string2c("DNS64 synthesis", req.pool)
-	ffi.C.kr_request_set_extended_error(req, kres.extended_error.FORGED, msg)
+	req:set_extended_error(kres.extended_error.FORGED, "BHD4: DNS64 synthesis")
 end
 
 local function hexchar2int(char)
diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua
index d54c96e8a543cbb24ed492a99df9ae7bfe87e117..306c4cf8a7dc9e162981efc55815834a5f8ce383 100644
--- a/modules/policy/policy.lua
+++ b/modules/policy/policy.lua
@@ -236,7 +236,7 @@ function policy.ANSWER(rtable, nodata)
 		ffi.C.kr_pkt_make_auth_header(answer)
 		local ttl = (data or {}).ttl or 1
 		answer:rcode(kres.rcode.NOERROR)
-		ffi.C.kr_request_set_extended_error(req, kres.extended_error.FORGED, nil)
+		req:set_extended_error(kres.extended_error.FORGED, "5DO5")
 
 		if data == nil then -- want NODATA, i.e. just a SOA
 			answer:begin(kres.section.AUTHORITY)
@@ -687,7 +687,7 @@ function policy.DENY_MSG(msg, extended_error)
 				   string.char(#msg) .. msg)
 
 		end
-		ffi.C.kr_request_set_extended_error(req, extended_error, nil)
+		req:set_extended_error(extended_error, "CR36")
 		return kres.DONE
 	end
 end
@@ -785,7 +785,7 @@ policy.DENY = policy.DENY_MSG() -- compatibility with < 2.0
 function policy.DROP(_, req)
 	local answer = answer_clear(req)
 	if answer == nil then return nil end
-	ffi.C.kr_request_set_extended_error(req, kres.extended_error.PROHIBITED, nil)
+	req:set_extended_error(kres.extended_error.PROHIBITED, "U5KL")
 	return kres.FAIL
 end
 
@@ -794,7 +794,7 @@ function policy.REFUSE(_, req)
 	if answer == nil then return nil end
 	answer:rcode(kres.rcode.REFUSED)
 	answer:ad(false)
-	ffi.C.kr_request_set_extended_error(req, kres.extended_error.PROHIBITED, nil)
+	req:set_extended_error(kres.extended_error.PROHIBITED, "EIM4")
 	return kres.DONE
 end
 
diff --git a/modules/refuse_nord/refuse_nord.c b/modules/refuse_nord/refuse_nord.c
index 4d84ae1d658d7ce816fca523038c5d5d1f289ce7..607ff6144782f3d1b5a366620a55ba099bf2f1ae 100644
--- a/modules/refuse_nord/refuse_nord.c
+++ b/modules/refuse_nord/refuse_nord.c
@@ -21,7 +21,7 @@ static int refuse_nord_query(kr_layer_t *ctx)
 		return ctx->state;
 	knot_wire_set_rcode(answer->wire, KNOT_RCODE_REFUSED);
 	knot_wire_clear_ad(answer->wire);
-	kr_request_set_extended_error(req, KNOT_EDNS_EDE_NOTAUTH, NULL);
+	kr_request_set_extended_error(req, KNOT_EDNS_EDE_NOTAUTH, "ABC4");
 	ctx->state = KR_STATE_DONE;
 	return ctx->state;
 }
diff --git a/modules/renumber/renumber.lua b/modules/renumber/renumber.lua
index b670695eec569da8cdd148455480ee6f009735d8..4272fbd1f0d464cf336b853c1acf8ee772098819 100644
--- a/modules/renumber/renumber.lua
+++ b/modules/renumber/renumber.lua
@@ -99,7 +99,7 @@ local function rule(prefixes)
 				pkt:put(rr.owner, rr.ttl, rr.class, rr.type, rr.rdata)
 			end
 		end
-		ffi.C.kr_request_set_extended_error(req, kres.extended_error.FORGED, nil)
+		req:set_extended_error(kres.extended_error.FORGED, "DUQR")
 		return state
 	end
 end