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

  1. Ensure the IUdpTest implementation returns a non-empty, well-formed request packet from BuildUdpRequestPacket (the built-in testers clone a static byte array).
  2. Verify the correct tester instance is injected into UdpTestService (DnsService, NtpService, StunService, or McBeService).
  3. Unit-test the tester's BuildUdpRequestPacket to assert a non-null, non-empty result.
  4. 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

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


AI-assisted analysis of 2dust/v2rayN@e01717d832 (2026-08-13). Data as JSON: /api/errors/70b52cdd3b44a48f. Report an issue: GitHub.