AdguardTeam/AdGuardHome · error
unknown cipher %q
Error message
unknown cipher %q
What it means
ParseCiphers maps human-readable cipher-suite names (e.g. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) to IDs; an unrecognized name yields this error. Only names present in the library's cipherSuites table are accepted.
Source
Thrown at internal/aghtls/aghtls.go:44
l.DebugContext(ctx, "known ciphers", "ciphers", cipherSuites)
}
// cipherSuites are a name-to-ID mapping of cipher suites from crypto/tls. It
// is filled by init. It must not be modified.
var cipherSuites map[string]uint16
// ParseCiphers parses a slice of cipher suites from cipher names.
func ParseCiphers(cipherNames []string) (cipherIDs []uint16, err error) {
if cipherNames == nil {
return nil, nil
}
cipherIDs = make([]uint16, 0, len(cipherNames))
for _, name := range cipherNames {
id, ok := cipherSuites[name]
if !ok {
return nil, fmt.Errorf("unknown cipher %q", name)
}
cipherIDs = append(cipherIDs, id)
}
return cipherIDs, nil
}
// SaferCipherSuites returns a set of default cipher suites with vulnerable and
// weak cipher suites removed.
func SaferCipherSuites() (safe []uint16) {
for _, s := range tls.CipherSuites() {
switch s.ID {
case
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA256,View on GitHub (pinned to b41aefbe51)
Solutions
- Log the exact offending name and correct it against the supported table in aghtls (cipherSuites map)
- Remove TLS 1.3 ciphers from the list — they are always enabled and not settable this way
- Trim whitespace and drop empty tokens before parsing
- Copy a known-good cipher list from the project's docs/tests
Example fix
// before
ciphers := []string{"tls_ecdhe_rsa_with_aes_128_gcm_sha256", "TLS_AES_128_GCM_SHA256"}
// after
// only TLS 1.2-style names, exact case, from the supported table
ciphers := []string{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"} Defensive patterns
Strategy: validation
Validate before calling
// validate against a known-good set before calling ParseCiphers:
for _, name := range cipherNames {
if !slices.Contains(supportedCipherNames, name) { return fmt.Errorf("bad cipher %q", name) }
} Type guard
func isValidCipherName(name string, table map[string]uint16) bool { _, ok := table[name]; return ok } Try / catch
ids, err := aghtls.ParseCiphers(names)
if err != nil && strings.Contains(err.Error(), "unknown cipher") {
// strip the offending name and re-validate, or fail config load with a clear message
} Prevention
- Source cipher lists from the library's supported table, not OpenSSL docs
- Exclude TLS 1.3 suite names from configurable lists
- Normalize input: trim spaces, drop empty tokens
- Validate config at load time before the TLS listener starts
When it happens
Trigger: Passing a cipher name with a typo, wrong case, outdated name, or a name not in the supported cipherSuites map (e.g. TLS 1.3 suite names like TLS_AES_128_GCM_SHA256, which are configured differently, or CBC/3DES suites excluded from the table).
Common situations: Copying cipher lists from nginx/OpenSSL configs that include names Go's crypto/tls or this table doesn't support; upgrading Go versions where cipher lists changed; extra whitespace or commas producing empty/garbage tokens.
Related errors
- loading tls certificate: %w
- parsing private key: %w
- certificate-key pair: %w
- tls: found unknown private key type %T in PKCS#8 wrapping
- parsing tls certificate: %w
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/1769fd73f71f4204.
Report an issue: GitHub.