TechnitiumSoftware/DnsServer · error · InvalidOperationException

DNS Server is already running.

Error message

DNS Server is already running.

What it means

Thrown by StartAsync when _state is not ServiceState.Stopped (i.e. already Starting, Running, or Stopping). The server is a single-instance state machine and cannot be started twice; the guard prevents overlapping listener binds.

Source

Thrown at DnsServerCore/Dns/DnsServer.cs:6637

            {
                if (!Socket.OSSupportsIPv6)
                    throw new DnsServerException(protocolName + " requires IPv6 support on the system to work.");

                throw new DnsServerException(protocolName + " is supported only on Windows 11 (build 22000 and later), Windows Server 2022 (and later), and Linux. On Linux, you must install 'libmsquic' manually.");
            }
        }

        #endregion

        #region public

        public async Task StartAsync(bool throwIfBindFails = false)
        {
            if (_disposed)
                ObjectDisposedException.ThrowIf(_disposed, this);

            if (_state != ServiceState.Stopped)
                throw new InvalidOperationException("DNS Server is already running.");

            _state = ServiceState.Starting;

            //bind on all local end points
            foreach (IPEndPoint localEP in _localEndPoints)
            {
                Socket udpListener = null;

                try
                {
                    udpListener = GetUdpListenerSocket(localEP.AddressFamily);

                    if ((localEP is InterfaceEndPoint intEP) && (intEP.InterfaceName is not null) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        try
                        {
                            udpListener.SetRawSocketOption(SOL_SOCKET, SO_BINDTODEVICE, Encoding.ASCII.GetBytes(intEP.InterfaceName));
                            _log.Write(localEP, DnsTransportProtocol.Udp, $"Socket was bound to device '{intEP.InterfaceName}' successfully.");

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Call StopAsync and await it fully before calling StartAsync again.
  2. Guard the call: only start when State == ServiceState.Stopped.
  3. Serialize start/stop with a lock or a single owner to prevent concurrent transitions.
  4. For config changes, use the in-process reload APIs rather than stop+start.

Example fix

// before
server.StartAsync();
// ... later, without stopping:
server.StartAsync();  // throws

// after
if (server.State != ServiceState.Stopped)
    await server.StopAsync();
await server.StartAsync();
Defensive patterns

Strategy: validation

Validate before calling

async Task SafeStartAsync(DnsServer server)
{
    if (server.State != ServiceState.Stopped) await server.StopAsync();
    await server.StartAsync();
}

Type guard

static bool IsStopped(IDnsServer s) => s.State == ServiceState.Stopped;

Try / catch

try { await server.StartAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already running")) { await server.StopAsync(); await server.StartAsync(); }

Prevention

When it happens

Trigger: Calling StartAsync a second time while the server is running or still starting; a restart routine that calls Start without waiting for StopAsync to complete; double-invoke from a UI button race.

Common situations: Host that auto-restarts on config change without stopping first; supervisor script firing twice; the previous StopAsync is still in progress (Stopping state) when Start is invoked.

Related errors


AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13). Data as JSON: /api/errors/6fb1ee3ccfab75d2. Report an issue: GitHub.