2dust/v2rayN · error · InvalidOperationException
Failed to build UDP request packet.
Error message
Failed to build UDP request packet.
What it means
Thrown by SendUdpRequestAsync when the injected IUdpTest.BuildUdpRequestPacket() returns null or an empty array. The service cannot send an empty datagram, so it aborts before opening the channel. In the shipped testers (Dns/Ntp/Stun/McBe) BuildUdpRequestPacket always returns a non-empty clone, so a hit indicates a misconfigured/null tester.
Source
Thrown at v2rayN/ServiceLib.UdpTest/UdpTestService.cs:98
var portStr = targetServerHost.Substring(lastColonIndex + 1);
if (ushort.TryParse(portStr, out var port))
{
return (host, port);
}
}
// No port specified, use default
return (targetServerHost, _udpTest.GetDefaultTargetPort());
}
public async Task<TimeSpan> SendUdpRequestAsync(string targetServerHost, int socks5Port, TimeSpan operationTimeout)
{
using var cts = new CancellationTokenSource(operationTimeout);
var cancellationToken = cts.Token;
var udpRequestPacket = _udpTest.BuildUdpRequestPacket();
if (udpRequestPacket == null || udpRequestPacket.Length == 0)
{
throw new InvalidOperationException("Failed to build UDP request packet.");
}
using var channel = new Socks5UdpChannel("127.0.0.1", socks5Port);
if (!await channel.EstablishUdpAssociationAsync(cancellationToken).ConfigureAwait(false))
{
throw new Exception("Failed to establish UDP association with SOCKS5 proxy.");
}
var (targetHost, targetPort) = ParseHostAndPort(targetServerHost);
byte[] udpReceiveResult = null;
// Get minimum round trip time from two attempts
var roundTripTime = TimeSpan.MaxValue;
for (var attempt = 0; attempt < 2; attempt++)
{
try
{View on GitHub (pinned to e01717d832)
Solutions
- Ensure the IUdpTest implementation returns a non-empty, well-formed request packet from BuildUdpRequestPacket (the built-in testers clone a static byte array).
- Verify the correct tester instance is injected into UdpTestService (DnsService, NtpService, StunService, or McBeService).
- Unit-test the tester's BuildUdpRequestPacket to assert a non-null, non-empty result.
- If extending IUdpTest, initialize the request packet in a static field or constructor so it is never null.
Example fix
// before - custom tester may return null/empty public byte[] BuildUdpRequestPacket() => _packet; // _packet could be null // after - guarantee a non-empty packet private static readonly byte[] Packet = /* ... */; public byte[] BuildUdpRequestPacket() => (byte[])Packet.Clone();
Defensive patterns
Strategy: validation
Validate before calling
// Validate the tester packet before sending
var packet = _udpTest.BuildUdpRequestPacket();
if (packet == null || packet.Length == 0)
throw new InvalidOperationException($"Tester {_udpTest.GetType().Name} produced an empty request packet."); Type guard
static bool IsValidUdpRequestPacket(byte[] packet) => packet != null && packet.Length > 0;
Try / catch
try
{
await SendUdpRequestAsync(host, port, timeout);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("build UDP request"))
{
// the injected IUdpTest is misconfigured; check DI registration / tester init
} Prevention
- Ensure custom IUdpTest implementations return a non-empty clone of a static request packet.
- Register the correct tester instance in DI.
- Unit-test BuildUdpRequestPacket for non-null/non-empty output.
When it happens
Trigger: SendUdpRequestAsync calls _udpTest.BuildUdpRequestPacket(); the result is null or Length == 0, raising InvalidOperationException before any socket work.
Common situations: A custom IUdpTest implementation returns null from BuildUdpRequestPacket; the tester was not initialized or its static query packet is empty; dependency injection wired a null/default tester.
Related errors
- webdav parameter error or null
- SOCKS5 address type {AddressType} not supported.
- Received NTP response is too short.
- Failed to verify and extract UDP response.
- Source directory not found: {dir.FullName}
AI-assisted analysis of 2dust/v2rayN@e01717d832 (2026-08-13).
Data as JSON: /api/errors/70b52cdd3b44a48f.
Report an issue: GitHub.