TechnitiumSoftware/DnsServer · error · DnsServerException
Unable to load daily stats.
Error message
Unable to load daily stats.
What it means
Thrown inside LoadDailyStats after a race: the code just built a fresh dailyStats, TryAdd failed (another thread inserted one first), and the follow-up TryGetValue also failed to retrieve it. Both the add and the lookup losing means the cache is being mutated concurrently in a way that removed the entry between the two calls. It is a defensive guard against an impossible-under-normal-locking cache state rather than a user-configurable error.
Source
Thrown at DnsServerCore/Dns/StatsManager.cs:573
for (int hour = 0; hour < 24; hour++) //hours
{
HourlyStats hourlyStats = LoadHourlyStats(dailyDateTime.AddHours(hour), ifNotExistsReturnEmptyHourlyStats: true);
dailyStats.Merge(hourlyStats.HourStat);
}
if (dailyStats.TotalQueries > 0)
{
_ = dailyStats.Truncate(DAILY_STATS_FILE_TOP_LIMIT);
SaveDailyStats(dailyDateTime, dailyStats);
GC.Collect();
}
}
if (!_dailyStatsCache.TryAdd(dailyDateTime, dailyStats))
{
if (!_dailyStatsCache.TryGetValue(dailyDateTime, out dailyStats))
throw new DnsServerException("Unable to load daily stats.");
}
}
return dailyStats;
}
private void SaveHourlyStats(DateTime dateTime, HourlyStats hourlyStats)
{
string hourlyStatsFile = Path.Combine(_statsFolder, dateTime.ToString("yyyyMMddHH", CultureInfo.InvariantCulture) + ".stat");
try
{
using (FileStream fS = new FileStream(hourlyStatsFile, FileMode.Create, FileAccess.Write))
{
hourlyStats.WriteTo(new BinaryWriter(fS));
}
}
catch (Exception ex)View on GitHub (pinned to d0484b6c1e)
Solutions
- Retry the stats read once; transient cache races usually resolve on the second call.
- Avoid toggling MaxStatFileDays between 0 and non-zero while the dashboard is polling, since that enables/disables the cleanup timer that can clear the cache.
- If it persists, restart the server to reset the stats cache; the underlying .stat files on disk are the source of truth and will be re-read.
- Report as a bug if reproducible, since both TryAdd and TryGetValue failing implies concurrent cache mutation that LoadDailyStats does not currently lock against.
Defensive patterns
Strategy: retry
Try / catch
// Retry once; the race is transient.
StatCounter daily;
for (int attempt = 0; attempt < 2; attempt++)
{
try { daily = statsManager.LoadDailyStats(date); break; }
catch (DnsServerException ex) when (ex.Message == "Unable to load daily stats." && attempt == 0)
{ continue; }
} Prevention
- Do not toggle MaxStatFileDays between 0 and non-zero while the dashboard polls.
- Avoid concurrent stats resets during dashboard refreshes.
- Restart the server if the error persists; .stat files on disk are the source of truth.
When it happens
Trigger: Concurrent calls to LoadDailyStats for the same date where one thread's TryAdd succeeds, the entry is then evicted/cleared (e.g. by MaxStatFileDays cleanup or a cache Clear), and the second thread's TryGetValue returns false. Extremely rare; indicates a cache-clear racing with load.
Common situations: Stats cleanup (MaxStatFileDays) clearing _dailyStatsCache while the dashboard requests stats for a day being loaded; concurrent dashboard refreshes during a stats reset; high concurrency plus aggressive MaxStatFileDays=0 toggling.
Related errors
- Failed to add Secondary node: please try again.
- Error while creating session. Please try again.
- Failed to delete Secondary node: please try again.
- DHCP Server is already running.
- DNS Server is already running.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/e168568ca4da1cd8.
Report an issue: GitHub.