diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go
index c95317a00551eeed2a6642dde62a0c04340d54b7..9dd2b31733dbdc1097fad95d52a2cafd69ac46ca 100644
--- a/p2p/discover/v5_udp.go
+++ b/p2p/discover/v5_udp.go
@@ -454,9 +454,20 @@ func (t *UDPv5) call(node *enode.Node, responseType byte, packet v5wire.Packet)
 
 // callDone tells dispatch that the active call is done.
 func (t *UDPv5) callDone(c *callV5) {
-	select {
-	case t.callDoneCh <- c:
-	case <-t.closeCtx.Done():
+	// This needs a loop because further responses may be incoming until the
+	// send to callDoneCh has completed. Such responses need to be discarded
+	// in order to avoid blocking the dispatch loop.
+	for {
+		select {
+		case <-c.ch:
+			// late response, discard.
+		case <-c.err:
+			// late error, discard.
+		case t.callDoneCh <- c:
+			return
+		case <-t.closeCtx.Done():
+			return
+		}
 	}
 }