TechnitiumSoftware/DnsServer · error · InvalidOperationException

Zone Signing Key (ZSK) automatic rollover cannot be set sinc

Error message

Zone Signing Key (ZSK) automatic rollover cannot be set since it is set to retire.

What it means

Thrown by RolloverDays setter on a ZSK that is in a valid rollover state (Generated/Published/Ready/Active) but has _isRetiring == true. The key has already been commanded to retire, so starting a new automatic rollover cycle on it is contradictory. The setter reaches this branch only after the value passes the >365 check and the state falls into one of the four active cases.

Source

Thrown at DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs:447

        public ushort RolloverDays
        {
            get { return _rolloverDays; }
            set
            {
                if (_keyType == DnssecPrivateKeyType.ZoneSigningKey)
                {
                    if (value > 365)
                        throw new ArgumentOutOfRangeException(nameof(RolloverDays), "Zone Signing Key (ZSK) automatic rollover days valid range is 0-365.");

                    switch (_state)
                    {
                        case DnssecPrivateKeyState.Generated:
                        case DnssecPrivateKeyState.Published:
                        case DnssecPrivateKeyState.Ready:
                        case DnssecPrivateKeyState.Active:
                            if (_isRetiring)
                                throw new InvalidOperationException("Zone Signing Key (ZSK) automatic rollover cannot be set since it is set to retire.");

                            break;

                        default:
                            throw new InvalidOperationException("Zone Signing Key (ZSK) automatic rollover cannot be set due to invalid key state.");
                    }
                }
                else
                {
                    if (value != 0)
                        throw new NotSupportedException("Automatic rollover is not supported for Key Signing Keys (KSK).");
                }

                _rolloverDays = value;
            }
        }

        public DnsDNSKEYRecordData DnsKey

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. If you want this key to keep serving with auto-rollover, first clear the retire flag (use the DNSSEC key lifecycle API to revoke retirement) so IsRetiring is false, then set RolloverDays.
  2. If retirement is intentional, leave RolloverDays unset / set it on a replacement key instead.
  3. Guard your config-restore logic to skip RolloverDays assignment for keys where IsRetiring is true.

Example fix

// before
key.RolloverDays = 30; // key.IsRetiring == true

// after
if (!key.IsRetiring)
    key.RolloverDays = 30;
else
    _log.Warn($"Skipped rollover days on retiring key {key.KeyTag}");
Defensive patterns

Strategy: validation

Validate before calling

if (key.KeyType == DnssecPrivateKeyType.ZoneSigningKey && days <= 365)
{
    if (key.IsRetiring)
        throw new InvalidOperationException("Cannot set rollover on a retiring key.");
    key.RolloverDays = (ushort)days;
}

Type guard

static bool CanSetRollover(DnssecPrivateKey k) =>
    k.KeyType == DnssecPrivateKeyType.ZoneSigningKey && !k.IsRetiring;

Try / catch

try { key.RolloverDays = (ushort)days; }
catch (InvalidOperationException ex) when (ex.Message.Contains("set to retire"))
{ /* cancel retirement first, or pick another key */ }

Prevention

When it happens

Trigger: Calling key.RolloverDays = N (N <= 365) on a ZSK whose State is Generated/Published/Ready/Active AND whose IsRetiring is already true. Typically happens when an operator re-enables auto-rollover on a key already scheduled for removal, or when a config restore reapplies RolloverDays to a retiring key.

Common situations: Mid-rollover the operator changes their mind and toggles auto-rollover back on without first cancelling retirement; a bulk DNSSEC config import sets RolloverDays on every key including ones flagged retiring.

Related errors


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