{"record":{"id":"831ccdb205ee16f7","repo":"TechnitiumSoftware/DnsServer","slug":"the-private-keys-must-contain-at-least-one-key-sig","errorCode":null,"errorMessage":"The private keys must contain at least one Key Signing Key.","messagePattern":"The private keys must contain at least one Key Signing Key\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":507,"sourceCode":"            bool foundKsk = false;\n            bool foundZsk = false;\n\n            foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)\n            {\n                switch (dnssecPrivateKey.KeyType)\n                {\n                    case DnssecPrivateKeyType.KeySigningKey:\n                        foundKsk = true;\n                        break;\n\n                    case DnssecPrivateKeyType.ZoneSigningKey:\n                        foundZsk = true;\n                        break;\n                }\n            }\n\n            if (!foundKsk)\n                throw new ArgumentException(\"The private keys must contain at least one Key Signing Key.\", nameof(dnssecPrivateKeys));\n\n            if (!foundZsk)\n                throw new ArgumentException(\"The private keys must contain at least one Zone Signing Key.\", nameof(dnssecPrivateKeys));\n\n            //load dnssec private keys\n            _dnssecPrivateKeys = new Dictionary<ushort, DnssecPrivateKey>(dnssecPrivateKeys.Count);\n\n            foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)\n                _dnssecPrivateKeys.Add(dnssecPrivateKey.KeyTag, dnssecPrivateKey);\n\n            //start zone signing\n            List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();\n            List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();\n\n            try\n            {\n                IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetApexZoneWithSubDomainZones(_name);\n","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L489-L525","documentation":"Thrown by the collection overload PrimaryZone.SignZone after scanning all dnssecPrivateKeys and finding no entry with KeyType == KeySigningKey. A valid signing set must contain at least one KSK (to produce the DNSKEY RRset signature and DS). The guard raises ArgumentException(nameof(dnssecPrivateKeys)).","triggerScenarios":"zone.SignZone(zskOnlyList, ...) — a collection with only ZoneSigningKey entries (or unknown types).","commonSituations":"Generating a batch of ZSKs and forgetting the KSK; loading keys filtered to the wrong role.","solutions":["Include at least one KeySigningKey in the collection passed to SignZone.","Validate the collection has both a KSK and a ZSK before calling.","Use the (ksk, zsk) overload if you only ever sign with one of each."],"exampleFix":"// before\nzone.SignZone(zsks, ttl, false);\n\n// after\nvar signingKeys = new[] { ksk }.Concat(zsks);\nzone.SignZone(signingKeys.ToList(), ttl, false);","handlingStrategy":"validation","validationCode":"if (!dnssecPrivateKeys.Any(k => k.KeyType == DnssecPrivateKeyType.KeySigningKey))\n    throw new ArgumentException(\"At least one KSK required.\");\nzone.SignZone(dnssecPrivateKeys, ttl, useNSec3);","typeGuard":"static bool HasKsk(IEnumerable<DnssecPrivateKey> ks) => ks.Any(k => k.KeyType == DnssecPrivateKeyType.KeySigningKey);","tryCatchPattern":null,"preventionTips":["Ensure the key set contains at least one KSK.","Validate both KSK and ZSK presence before signing.","Use the (ksk, zsk) overload for single-key-pair signing."],"tags":["csharp","dns","dnssec","validation","technitium-dns"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}