TechnitiumSoftware/DnsServer · warning · InvalidDataException

HourlyStats format is invalid.

Error message

HourlyStats format is invalid.

What it means

Thrown by the HourlyStats(BinaryReader) constructor when the first two ASCII bytes of the stream are not 'HS'. The magic header is a format guard read before the version byte: it confirms the stream is actually an hourly .stat file and not a corrupt or foreign file. Failing here means the file is not an HourlyStats file at all.

Source

Thrown at DnsServerCore/Dns/StatsManager.cs:1745

            #region constructor

            public HourlyStats()
            {
                _hourStat = new StatCounter();
                _hourStat.Lock();

                for (int i = 0; i < _minuteStats.Length; i++)
                {
                    _minuteStats[i] = new StatCounter();
                    _minuteStats[i].Lock();
                }
            }

            public HourlyStats(BinaryReader bR)
            {
                if (Encoding.ASCII.GetString(bR.BaseStream.ReadExactly(2)) != "HS") //format
                    throw new InvalidDataException("HourlyStats format is invalid.");

                byte version = bR.ReadByte();
                switch (version)
                {
                    case 1:
                        _hourStat = new StatCounter();
                        _hourStat.Lock();

                        for (int i = 0; i < _minuteStats.Length; i++)
                        {
                            _minuteStats[i] = new StatCounter(bR);
                            _hourStat.Merge(_minuteStats[i]);
                        }

                        break;

                    default:
                        throw new InvalidDataException("HourlyStats version not supported.");

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Delete the offending .stat file (named yyyyMMddHH.stat) so the hour is treated as empty and re-accumulated going forward.
  2. Verify the stats folder contains only files written by the server; remove foreign files.
  3. Ensure the server is stopped before backing up or copying stats files to avoid catching a half-written file.
Defensive patterns

Strategy: fallback

Validate before calling

// Skip non-HourlyStats files when scanning the stats folder.
using var fs = File.OpenRead(path);
Span<byte> magic = stackalloc byte[2];
if (fs.Read(magic) != 2 || magic[0] != (byte)'H' || magic[1] != (byte)'S')
    continue; // not an HourlyStats file; ignore

Try / catch

try { hourly = new HourlyStats(bR); }
catch (InvalidDataException ex) when (ex.Message == "HourlyStats format is invalid.")
{ hourly = HourlyStats.Empty; /* treat as empty hour */ }

Prevention

When it happens

Trigger: Opening a file in the stats folder as an HourlyStats stream when its first two bytes are not 0x48 0x53 ('HS'). Caused by a truncated/zero-byte file, a corrupt file, a non-stat file placed in the stats folder, or a partially-written file from a crash.

Common situations: Crash during stats write leaves a zero-length or partial .stat; an external process writes a file into the stats directory; disk corruption; copying unrelated files into the stats folder.

Related errors


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