{"record":{"id":"c748b502fa9baab7","repo":"TechnitiumSoftware/DnsServer","slug":"statcounter-format-is-invalid","errorCode":null,"errorMessage":"StatCounter format is invalid.","messagePattern":"StatCounter format is invalid\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"warning","filePath":"DnsServerCore/Dns/StatsManager.cs","lineNumber":1870,"sourceCode":"\n            #endregion\n\n            #region constructor\n\n            public StatCounter()\n            {\n                _queryDomains = new ConcurrentDictionary<string, Counter>();\n                _queryBlockedDomains = new ConcurrentDictionary<string, Counter>();\n                _queryTypes = new ConcurrentDictionary<DnsResourceRecordType, Counter>();\n                _protocolTypes = new ConcurrentDictionary<DnsTransportProtocol, Counter>();\n                _clientIpAddressesUdpTcp = new ConcurrentDictionary<IPAddress, (Counter, Counter)>();\n                _queries = new ConcurrentDictionary<DnsQuestionRecord, Counter>();\n            }\n\n            public StatCounter(BinaryReader bR)\n            {\n                if (Encoding.ASCII.GetString(bR.BaseStream.ReadExactly(2)) != \"SC\") //format\n                    throw new InvalidDataException(\"StatCounter format is invalid.\");\n\n                byte version = bR.ReadByte();\n                switch (version)\n                {\n                    case 1:\n                    case 2:\n                    case 3:\n                    case 4:\n                    case 5:\n                    case 6:\n                        _totalQueries = bR.ReadInt32();\n                        _totalNoError = bR.ReadInt32();\n                        _totalServerFailure = bR.ReadInt32();\n                        _totalNxDomain = bR.ReadInt32();\n                        _totalRefused = bR.ReadInt32();\n\n                        if (version >= 3)\n                        {","sourceCodeStart":1852,"sourceCodeEnd":1888,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/StatsManager.cs#L1852-L1888","documentation":"Thrown by the StatCounter(BinaryReader) constructor when the first two ASCII bytes are not 'SC'. StatCounter is the granular stats record (per-minute, per-hour, per-day) persisted in .stat files. The 'SC' magic guards against reading a non-StatCounter or corrupt stream before the version byte is consumed.","triggerScenarios":"Deserializing a StatCounter from a stream whose first two bytes are not 0x53 0x43 ('SC'). Caused by a truncated/zero-byte file, corruption, a foreign file in the stats folder, or a partially-written stats file.","commonSituations":"Crash mid-write leaves a partial .stat; disk corruption; external tool writing into the stats folder; backup restored from a partial copy.","solutions":["Delete the offending .stat file so the affected period is treated as empty.","Audit the stats folder for foreign or zero-byte files and remove them.","Stop the server before backing up stats to avoid capturing half-written files."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Skip non-StatCounter files when scanning the stats folder.\nSpan<byte> magic = stackalloc byte[2];\nif (fs.Read(magic) != 2 || magic[0] != (byte)'S' || magic[1] != (byte)'C')\n    continue;","typeGuard":null,"tryCatchPattern":"try { counter = new StatCounter(bR); }\ncatch (InvalidDataException ex) when (ex.Message == \"StatCounter format is invalid.\")\n{ counter = new StatCounter(); }","preventionTips":["Stop the server before backing up or copying stats files.","Remove zero-byte or foreign files from the stats folder."],"tags":["stats","stat-counter","serialization","deserialization","corruption"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}