{"record":{"id":"e62e030e7dfb1633","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-update-dnskey-ttl-value-one-or-more-privat","errorCode":null,"errorMessage":"Cannot update DNSKEY TTL value: one or more private keys have state other than Ready or Active.","messagePattern":"Cannot update DNSKEY TTL value: one or more private keys have state other than Ready or Active\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"warning","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":2461,"sourceCode":"        }\n\n        public void UpdateDnsKeyTtl(uint dnsKeyTtl)\n        {\n            if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)\n                throw new DnsServerException(\"The zone must be signed.\");\n\n            lock (_dnssecPrivateKeys)\n            {\n                foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)\n                {\n                    switch (privateKeyEntry.Value.State)\n                    {\n                        case DnssecPrivateKeyState.Ready:\n                        case DnssecPrivateKeyState.Active:\n                            break;\n\n                        default:\n                            throw new DnsServerException(\"Cannot update DNSKEY TTL value: one or more private keys have state other than Ready or Active.\");\n                    }\n                }\n            }\n\n            if (!_entries.TryGetValue(DnsResourceRecordType.DNSKEY, out IReadOnlyList<DnsResourceRecord> dnsKeyRecords))\n                throw new InvalidOperationException();\n\n            DnsResourceRecord[] newDnsKeyRecords = new DnsResourceRecord[dnsKeyRecords.Count];\n\n            for (int i = 0; i < dnsKeyRecords.Count; i++)\n            {\n                DnsResourceRecord dnsKeyRecord = dnsKeyRecords[i];\n                newDnsKeyRecords[i] = new DnsResourceRecord(dnsKeyRecord.Name, DnsResourceRecordType.DNSKEY, DnsClass.IN, dnsKeyTtl, dnsKeyRecord.RDATA);\n            }\n\n            List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();\n            List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();\n","sourceCodeStart":2443,"sourceCodeEnd":2479,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L2443-L2479","documentation":"Thrown inside UpdateDnsKeyTtl() while iterating the zone's DNSSEC private keys under a lock. Only keys in DnssecPrivateKeyState.Ready or DnssecPrivateKeyState.Active are stable enough to re-sign a DNSKEY RRset whose TTL changed. Any key still in a transitional state (Generated, Published, or a rollover/publish/retire state) means the key set is mid-rollover and the TTL change cannot be applied atomically with a consistent signature.","triggerScenarios":"Calling UpdateDnsKeyTtl during an active key rollover when at least one DnssecPrivateKey.State is neither Ready nor Active (e.g. Generated, Published, or a publish/retire phase). Triggered by changing the DNSKEY TTL while a scheduled KSK/ZSK rollover is in progress.","commonSituations":"Operator triggers an emergency TTL change during a routine ZSK pre-publication; automation that periodically normalizes DNSKEY TTLs collides with a rollover schedule; manually advancing key states leaves one key stuck in Published.","solutions":["Wait for the active key rollover to finish so every key reaches Ready or Active, then retry UpdateDnsKeyTtl.","Inspect each private key's State via the DNSSEC key management API and advance or complete the rollover for any non-stable key before retrying.","If a key is stuck in a transitional state due to a failed rollover, resolve/abort that key's rollover state, then retry the TTL update."],"exampleFix":"// before\nzone.UpdateDnsKeyTtl(desiredTtl); // throws mid-rollover\n\n// after\nif (AllKeysStable(zone)) // every key.State is Ready or Active\n    zone.UpdateDnsKeyTtl(desiredTtl);\nelse\n    Log.Warn(\"Skip DNSKEY TTL update: key rollover in progress\");","handlingStrategy":"validation","validationCode":"// Verify every private key is stable (Ready/Active) before updating TTL.\nbool AllKeysStableForTtlUpdate(Zone zone) =>\n    GetDnssecPrivateKeys(zone).All(k =>\n        k.State == DnssecPrivateKeyState.Ready ||\n        k.State == DnssecPrivateKeyState.Active);\n\nif (AllKeysStableForTtlUpdate(zone))\n    zone.UpdateDnsKeyTtl(desiredTtl);\nelse\n    Log.Warn(\"DNSKEY TTL update skipped: a key rollover is in progress.\");","typeGuard":"static bool CanUpdateDnsKeyTtlNow(Zone zone) =>\n    GetDnssecPrivateKeys(zone).All(k =>\n        k.State == DnssecPrivateKeyState.Ready ||\n        k.State == DnssecPrivateKeyState.Active);","tryCatchPattern":"try { zone.UpdateDnsKeyTtl(ttl); }\ncatch (DnsServerException ex) when (ex.Message.Contains(\"state other than Ready or Active\"))\n{ Log.Warn($\"Key rollover in progress; retry later: {ex.Message}\"); }","preventionTips":["Schedule DNSKEY TTL changes outside key-rollover windows.","Expose key states in monitoring so transitional states are visible.","Retry on this specific message after rollover completion rather than treating it as a hard failure."],"tags":["dns","dnssec","dnskey","ttl","key-rollover","validation"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}