{"record":{"id":"979818ea9adbc50b","repo":"coredns/coredns","slug":"rr-in-q-is-not-a-dnskey-d","errorCode":null,"errorMessage":"RR in %q is not a DNSKEY: %d","messagePattern":"RR in %q is not a DNSKEY: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/sign/keys.go","lineNumber":82,"sourceCode":"\n\treturn pairs, nil\n}\n\nfunc readKeyPair(public, private string) (Pair, error) {\n\trk, err := os.Open(filepath.Clean(public))\n\tif err != nil {\n\t\treturn Pair{}, err\n\t}\n\tb, err := io.ReadAll(rk)\n\tif err != nil {\n\t\treturn Pair{}, err\n\t}\n\tdnskey, err := dns.NewRR(string(b))\n\tif err != nil {\n\t\treturn Pair{}, err\n\t}\n\tif _, ok := dnskey.(*dns.DNSKEY); !ok {\n\t\treturn Pair{}, fmt.Errorf(\"RR in %q is not a DNSKEY: %d\", public, dnskey.Header().Rrtype)\n\t}\n\tksk := dnskey.(*dns.DNSKEY).Flags&(1<<8) == (1<<8) && dnskey.(*dns.DNSKEY).Flags&1 == 1\n\tif !ksk {\n\t\treturn Pair{}, fmt.Errorf(\"DNSKEY in %q is not a CSK/KSK\", public)\n\t}\n\n\trp, err := os.Open(filepath.Clean(private))\n\tif err != nil {\n\t\treturn Pair{}, err\n\t}\n\tprivkey, err := dnskey.(*dns.DNSKEY).ReadPrivateKey(rp, private)\n\tif err != nil {\n\t\treturn Pair{}, err\n\t}\n\tswitch signer := privkey.(type) {\n\tcase *ecdsa.PrivateKey:\n\t\treturn Pair{Public: dnskey.(*dns.DNSKEY), KeyTag: dnskey.(*dns.DNSKEY).KeyTag(), Private: signer}, nil\n\tcase ed25519.PrivateKey:","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/coredns/coredns/blob/558c9757a92b361e550bdba82d0b4ddf3d12d595/plugin/sign/keys.go#L64-L100","documentation":"When reading a DNSSEC key pair, readKeyPair parses the public key file into an RR and verifies it is a DNSKEY record. If dns.NewRR yields a record of any other type (checked via type assertion), the plugin rejects the pair, reporting the actual record type number found in the file.","triggerScenarios":"Passing a file that is not a DNSKEY RR — e.g. a DS record, a zone file fragment, an HTML error page from a failed key download, or a DNSKEY response including RRSIG — as the public key argument to the keys directive.","commonSituations":"Downloading a key from a DNS lookup and saving the wrong RR (DS instead of DNSKEY); using ldns-verify output or a .key file that actually holds a DS; key file mixed up with zone data.","solutions":["Regenerate or export the correct DNSKEY public key file (e.g. with dnssec-keygen / delv output)","Confirm the .key file's first record line starts with the zone name and 'IN DNSKEY'","Re-download the key ensuring you capture the DNSKEY RR, not the DS or other records from the query","Point the keys directive at the K<zone>+alg+tag.key file produced by dnssec-keygen"],"exampleFix":"// before (key file holds a DS record)\nexample.org. 3600 IN DS 12345 13 2 abcdef...\n// after (key file must hold DNSKEY)\nexample.org. 3600 IN DNSKEY 257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0dxCjjnopKl+GqJxpVXckHAeF+KkxLbxILfDLUT0nAKFkXe3a0uPcaU==","handlingStrategy":"validation","validationCode":"// Verify the public key file contains a DNSKEY RR before use:\nb, _ := os.ReadFile(publicKeyPath)\nrr, err := dns.NewRR(string(b))\nif err != nil || _, ok := rr.(*dns.DNSKEY); !ok {\n    // not a DNSKEY; regenerate or re-export\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure the .key file exported is a DNSKEY, not DS or other RR types","Use dnssec-keygen output files directly rather than re-typing key material","Check file contents start with 'IN DNSKEY' before referencing","Keep key files separate from zone data files to avoid mixups"],"tags":["dnssec","dnskey","key-format","sign"],"backgroundTag":"unexpected-response-shape","analyzedSha":"558c9757a92b361e550bdba82d0b4ddf3d12d595","analyzedAt":"2026-09-06T22:47:02.106Z","contentChangedAt":"2026-09-06T22:47:02.106Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}