TechnitiumSoftware/DnsServer · error · DnsWebServiceException
The DNS web service is already running.
Error message
The DNS web service is already running.
What it means
Thrown by DnsWebService.StartAsync() as a re-entrancy guard: it checks the private _isRunning flag (set true only after a fully successful start at line 2956, cleared by StopAsync()/DisposeAsync at line 2986) and refuses to start a second concurrent instance. It is a DnsWebServiceException (custom Exception subclass), not an InvalidOperationException, so callers catching generic exceptions still see it. The library throws it because StartAsync initializes DNS/DHCP servers, binds TCP/UDP listeners, and rewrites config — running it twice would double-bind ports and corrupt shared managers.
Source
Thrown at DnsServerCore/DnsWebService.cs:2883
{
_authManager.RemoveAllPermissions(PermissionSection.Zones, e.ZoneInfo.Name);
_authManager.SaveConfigFile();
//delete cache for this zone to allow rebuilding cache data without using the current zone
_dnsServer.CacheZoneManager.DeleteZone(e.ZoneInfo.Name);
}
#endregion
#region public
public async Task StartAsync(bool throwIfBindFails = false)
{
if (_disposed)
ObjectDisposedException.ThrowIf(_disposed, this);
if (_isRunning)
throw new DnsWebServiceException("The DNS web service is already running.");
try
{
//init dns server
_dnsServer = new DnsServer(_configFolder, Path.Combine(_appFolder, "dohwww"), _log);
//init dhcp server
_dhcpServer = new DhcpServer(Path.Combine(_configFolder, "scopes"), _log);
_dhcpServer.DnsServer = _dnsServer;
_dhcpServer.AuthManager = _authManager;
//load web service config file
LoadConfigFile();
//load dns config file
_dnsServer.LoadConfigFile();
//load all dns applicationsView on GitHub (pinned to d0484b6c1e)
Solutions
- Await StopAsync() (or DisposeAsync) on the existing instance and wait for it to complete before calling StartAsync() again — StartAsync only succeeds from the stopped state.
- If restarting, replace the instance entirely: dispose the old DnsWebService, create a new one, then StartAsync. This avoids any half-stopped state.
- Ensure StartAsync is driven from a single owner (one IHostedService / one background service) and guard the call site with your own _started flag so retry/idempotency logic never double-invokes it.
- If a previous StartAsync threw, _isRunning stays false, so retrying StartAsync is safe — but verify via logs that the prior attempt actually failed rather than partially bound ports before retrying.
Example fix
// before
await webService.StartAsync();
// ... later, 'reload' handler mistakenly calls it again
await webService.StartAsync(); // throws DnsWebServiceException
// after
if (webService is not null)
await webService.StopAsync();
await webService.StartAsync(throwIfBindFails: true); Defensive patterns
Strategy: try-catch
Validate before calling
// _isRunning is private with no public accessor, so track ownership at the call site.
// The caller must keep its own start/stop bookkeeping.
private int _started; // 0 = stopped, 1 = running
public async Task StartOnceAsync(DnsWebService svc, bool throwIfBindFails = false)
{
if (Interlocked.CompareExchange(ref _started, 1, 0) != 0)
return; // already started; avoid the double-start throw
try
{
await svc.StartAsync(throwIfBindFails);
}
catch
{
Volatile.Write(ref _started, 0); // start failed, _isRunning stayed false
throw;
}
}
public async Task StopOnceAsync(DnsWebService svc)
{
if (Interlocked.CompareExchange(ref _started, 0, 1) != 1)
return;
await svc.StopAsync();
} Type guard
// No public IsRunning exists; mirror the library's own state with a single-owner flag.
bool IsServiceRunning(DnsWebService svc, ref int startedFlag)
=> Volatile.Read(ref startedFlag) == 1 && svc is not null; Try / catch
try
{
await webService.StartAsync(throwIfBindFails: true);
}
catch (DnsWebServiceException ex) when (ex.Message.Contains("already running"))
{
// Recover by stopping first, then starting once.
await webService.StopAsync();
await webService.StartAsync(throwIfBindFails: true);
}
// Do NOT swallow other DnsWebServiceException variants (bind failures, etc.) —
// rethrow them so the caller knows the service is not up. Prevention
- Own StartAsync/StopAsync from exactly one component (a single IHostedService or background service); never invoke StartAsync from event handlers or health probes.
- Before any restart, always await StopAsync() to completion — StartAsync is not idempotent and _isRunning only flips inside StopAsync.
- Keep a local started flag (Interlocked) so retry/idempotency code cannot reach StartAsync while the service is up.
- Treat a failed StartAsync as 'definitely stopped': _isRunning is set only at the very end of success, so retrying after a genuine failure is safe — but confirm via logs that it was a failure, not a successful start you mistook for one.
- Use one DnsWebService instance per config folder; sharing the folder across instances causes both port-bind races and this guard.
When it happens
Trigger: Calling webService.StartAsync() a second time on the same DnsWebService instance without an intervening await StopAsync(). This happens in restart loops that call StartAsync again before the previous start finished, in DI/hosted-service code where StartAsync is invoked from two paths (e.g. a health-check re-trigger and a startup hook), or when the caller assumes a failed start left the service stopped (it does — _isRunning stays false on failure — but the caller retried after a *successful* start).
Common situations: A generic-host IHostedService wrapper whose StartAsync is invoked by the host and then again by application code; a 'reload settings' feature that re-runs StartAsync instead of Stop+Start; container orchestrator (k8s liveness) sidecars issuing restart commands; multiple DnsWebService instances pointing at the same config folder where one is already bound to ports 5380/53443.
Related errors
- AddressFamily not supported.
- Failed to read 'Zones' permissions: auth.config file is prob
- Failed to find 'Administrators' group: auth.config file is p
- Failed to find 'DNS Administrators' group: auth.config file
- Web Service config file format is invalid.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/dbf45e6d76bad4e5.
Report an issue: GitHub.