TechnitiumSoftware/DnsServer · error · DnsServerException
Failed to sign record set: {extendedDnsErrorCode}
Error message
Failed to sign record set: {extendedDnsErrorCode} What it means
Thrown by DnssecPrivateKey.SignRRSet after DnsRRSIGRecordData.TryGetRRSetHash returns false. The hash step (RFC 4034 §3.1.8) builds the canonical RRset wire image to sign, and TryGetRRSetHash validates that image before hashing. When it fails it reports an EDnsExtendedDnsErrorCode describing exactly what was inconsistent (e.g. mixed record names/types/classes, or an RRSIG field that does not match the RRset). The message stringifies that code so the operator can see why canonicalization broke.
Source
Thrown at DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs:353
}
protected abstract byte[] SignHash(byte[] hash);
protected abstract void ReadPrivateKeyFrom(BinaryReader bR);
protected abstract void WritePrivateKeyTo(BinaryWriter bW);
#endregion
#region internal
internal DnsResourceRecord SignRRSet(string signersName, IReadOnlyList<DnsResourceRecord> records, uint signatureInceptionOffset, uint signatureValidityPeriod)
{
DnsResourceRecord firstRecord = records[0];
DnsRRSIGRecordData unsignedRRSigRecord = new DnsRRSIGRecordData(firstRecord.Type, _algorithm, DnsRRSIGRecordData.GetLabelCount(firstRecord.Name), firstRecord.OriginalTtlValue, Convert.ToUInt32((DateTime.UtcNow.AddSeconds(signatureValidityPeriod) - DateTime.UnixEpoch).TotalSeconds % uint.MaxValue), Convert.ToUInt32((DateTime.UtcNow.AddSeconds(-signatureInceptionOffset) - DateTime.UnixEpoch).TotalSeconds % uint.MaxValue), DnsKey.ComputedKeyTag, signersName, null);
if (!DnsRRSIGRecordData.TryGetRRSetHash(unsignedRRSigRecord, records, out byte[] hash, out EDnsExtendedDnsErrorCode extendedDnsErrorCode))
throw new DnsServerException("Failed to sign record set: " + extendedDnsErrorCode.ToString());
byte[] signature = SignHash(hash);
DnsRRSIGRecordData signedRRSigRecord = new DnsRRSIGRecordData(unsignedRRSigRecord.TypeCovered, unsignedRRSigRecord.Algorithm, unsignedRRSigRecord.Labels, unsignedRRSigRecord.OriginalTtl, unsignedRRSigRecord.SignatureExpiration, unsignedRRSigRecord.SignatureInception, unsignedRRSigRecord.KeyTag, unsignedRRSigRecord.SignersName, signature);
return new DnsResourceRecord(firstRecord.Name, DnsResourceRecordType.RRSIG, firstRecord.Class, firstRecord.OriginalTtlValue, signedRRSigRecord);
}
internal void SetState(DnssecPrivateKeyState state, uint stateTransitionInTtl = 0)
{
if (_state >= state)
return; //ignore; state cannot be updated to lower value
_state = state;
_stateChangedOn = DateTime.UtcNow;
if (stateTransitionInTtl > 0)
_stateTransitionBy = _stateChangedOn.AddSeconds(stateTransitionInTtl);
elseView on GitHub (pinned to d0484b6c1e)
Solutions
- Inspect the extendedDnsErrorCode in the message: it names the precise canonicalization rule that failed (name/type/class mismatch). Fix the RRset so every record shares one name, one type, one class.
- Verify the records list is non-empty and homogeneous before calling SignRRSet; filter out RRSIG/CNAME/NSEC entries that do not belong to the RRset being signed.
- Check that the DnsKey key tag, algorithm, and signersName on the signing key match what the RRset expects.
- If the error appears during automatic zone signing, open the zone in the web console, find the offending record set (the zone log names it), correct or delete it, and re-trigger signing.
Example fix
// before
var rrsig = key.SignRRSet(zoneName, allRecords, -300, 30 * 86400); // allRecords mixes A + AAAA + CNAME
// after
var aRecords = allRecords.Where(r => r.Type == DnsResourceRecordType.A)
.Where(r => r.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
.ToList();
if (aRecords.Count > 0)
var rrsig = key.SignRRSet(zoneName, aRecords, -300, 30 * 86400); Defensive patterns
Strategy: validation
Validate before calling
// Validate an RRset is canonical before signing.
static bool IsValidRrsetForSigning(IReadOnlyList<DnsResourceRecord> records)
{
if (records is null || records.Count == 0) return false;
string name = records[0].Name;
var type = records[0].Type;
var cls = records[0].Class;
for (int i = 1; i < records.Count; i++)
{
if (!records[i].Name.Equals(name, StringComparison.OrdinalIgnoreCase)) return false;
if (records[i].Type != type) return false;
if (records[i].Class != cls) return false;
// RRSIG/CNAME/NSEC must not be in the RRset being signed
if (records[i].Type == DnsResourceRecordType.RRSIG ||
records[i].Type == DnsResourceRecordType.CNAME ||
records[i].Type == DnsResourceRecordType.NSEC) return false;
}
return true;
} Try / catch
// Catch only around the signing call; log extendedDnsErrorCode and skip the RRset.
try
{
var rrsig = key.SignRRSet(signer, rrset, inceptionOffset, validity);
}
catch (DnsServerException ex) when (ex.Message.StartsWith("Failed to sign record set:"))
{
_log.Error($"Skipped signing RRset {rrset[0].Name} {rrset[0].Type}: {ex.Message}");
} Prevention
- Group records into homogeneous RRsets (same name, type, class) before signing; never mix.
- Filter RRSIG, CNAME, and NSEC records out of a set before passing it to SignRRSet.
- Confirm the signing key's algorithm, key tag, and signersName match the records.
When it happens
Trigger: Calling SignRRSet(signersName, records, ...) with a records list whose members do not form a valid RRset: more than one name, more than one type, mismatched class, CNAME/RRSIG/NSEC records mixed in, an empty list (records[0] already IndexOutOfRange before this), or an unsignedRRSigRecord whose TypeCovered/KeyTag/SignersName disagree with the records. It can also fire if the underlying ManagedDns canonicalization rejects the input.
Common situations: A zone signing pass encounters corrupt or hand-edited authoritative records; a custom App that assembles an RRset to sign groups unrelated records together; a downgrade then upgrade cycle left records whose canonical form changed; DNSSEC signing a zone with CNAME chains mistakenly placed in one RRset.
Related errors
- Cannot set DNSSEC records.
- Cannot add DNSSEC record.
- Valid RSA ({(keyType == DnssecPrivateKeyType.KeySigningKey ?
- Zone Signing Key (ZSK) automatic rollover days valid range i
- Automatic rollover is not supported for Key Signing Keys (KS
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/8aa942f79e6988d7.
Report an issue: GitHub.