{"record":{"id":"8c12cbb834edb800","repo":"cilium/cilium","slug":"cannot-forward-proxied-dns-response-w","errorCode":null,"errorMessage":"Cannot forward proxied DNS response: %w","messagePattern":"Cannot forward proxied DNS response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/fqdn/dnsproxy/proxy.go","lineNumber":1138,"sourceCode":"\tscopedLog.Debug(\"Notifying with DNS response to original DNS query\")\n\tif err := p.NotifyOnDNSMsg(time.Now(), ep, epIPPort, targetServerID, targetServer, responseDetails, protocol, true, &stat); err != nil {\n\t\tscopedLog.Error(\n\t\t\t\"Failed to process DNS response\",\n\t\t\tlogfields.Error, err,\n\t\t\tlogfields.Response, response,\n\t\t)\n\t\tp.sendErrorResponse(scopedLog, w, request, false)\n\t\treturn\n\t}\n\n\tscopedLog.Debug(\"Responding to original DNS query\")\n\t// Ensure the ID matches the initial request - the upstream query may have changed the ID to avoid duplicates.\n\tresponse.Id = requestID\n\tresponse.Compress = p.EnableDNSCompression && shouldCompressResponse(request, response)\n\terr = w.WriteMsg(response)\n\tif err != nil {\n\t\tscopedLog.Error(\"Cannot forward proxied DNS response\", logfields.Error, err)\n\t\tstat.Err = fmt.Errorf(\"Cannot forward proxied DNS response: %w\", err)\n\t\tp.NotifyOnDNSMsg(time.Now(), ep, epIPPort, targetServerID, targetServer, responseDetails, protocol, true, &stat)\n\t} else {\n\t\tp.Lock()\n\t\t// Add the server to the set of used DNS servers. This set is never GCd, but is limited by set\n\t\t// of DNS server IPs that are allowed by a policy and for which successful response was received.\n\t\tp.usedServers[targetServer.Addr()] = struct{}{}\n\t\tp.Unlock()\n\t}\n}\n\nfunc (p *DNSProxy) enforceConcurrencyLimit(ctx context.Context) error {\n\tif p.ConcurrencyGracePeriod == 0 {\n\t\t// No grace time configured. Failing to acquire semaphore means\n\t\t// immediately give up.\n\t\tif !p.ConcurrencyLimit.TryAcquire(1) {\n\t\t\treturn ErrFailedAcquireSemaphore{\n\t\t\t\tparallel: option.Config.DNSProxyConcurrencyLimit,\n\t\t\t}","sourceCodeStart":1120,"sourceCodeEnd":1156,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/fqdn/dnsproxy/proxy.go#L1120-L1156","documentation":"Writing the (already received and processed) upstream DNS response back to the original client failed via w.WriteMsg. The client typically sees no answer and retries; note the server is still added/no success bookkeeping is skipped since the write failed.","triggerScenarios":"w.WriteMsg(response) errors after a successful upstream exchange - client went away (UDP client timed out and freed the port, TCP connection closed by peer), connection reset, or the underlying socket buffer/MTU rejects the packet (oversized UDP response with truncation handling issues).","commonSituations":"Slow upstream exceeding the client resolver's own timeout so the client abandons the query; NAT conntrack entry expired dropping the return packet; TCP RST because the client closed the connection; response too large for UDP path and truncation mishandled.","solutions":["Check for client-side resolver timeouts: if upstream latency is near client timeout, lower ProxyForwardTimeout or speed up the upstream.","Verify NAT/conntrack is not dropping return traffic (conntrack -L, check DROP counters).","Enable DNS compression (EnableDNSCompression) to shrink large responses under UDP size limits.","Look for EDNS0/truncation handling: ensure clients use EDNS or fall back to TCP for large answers.","Inspect the wrapped error: 'connection refused'/'no such file' implies client vanished; retry behavior is on the client side."],"exampleFix":"// before: large responses dropped over UDP\n// after: enable compression in proxy construction\ndnsproxy.NewDNSProxy(..., dnsproxy.EnableDNSCompression) // Compress=true for >512B responses","handlingStrategy":"fallback","validationCode":"// Verify the client is still reachable before a long upstream wait:\nif tcpConn, ok := w.(interface{ Close() error }); ok {\n    _ = tcpConn // for TCP, detect closed conns via read deadlines / keepalives\n}","typeGuard":"func isUDPWriter(w dns.ResponseWriter) bool {\n    return strings.HasPrefix(w.RemoteAddr().Network(), \"udp\")\n}","tryCatchPattern":"if err := w.WriteMsg(response); err != nil {\n    // client likely gone; do not retry - rely on client resolver re-querying\n    log.Warn(\"client write failed; client probably abandoned query\", \"err\", err)\n}","preventionTips":["Keep upstream latency well below client resolver timeout so the client is still waiting.","Enable EnableDNSCompression to avoid oversized UDP responses.","Ensure NAT/conntrack timeouts exceed DNS round-trip times.","Rely on client retry semantics; this error is usually self-healing."],"tags":["dns","network","write-failed"],"backgroundTag":"dns-response-write-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}