caddyserver/caddy · error

unrecognized key type: %s

Error message

unrecognized key type: %s

What it means

After placeholder expansion, the automation policy's key_type is not one of the supported certificate key types. Caddy's supportedCertKeyTypes map accepts exactly: rsa2048, rsa4096, p256, p384, ed25519. Anything else — including common guesses like 'RSA2048', 'rsa', 'P256', 'ecdsa', or 'ed' — is rejected.

Source

Thrown at modules/caddytls/automation.go:282

	}

	return nil
}

// makeCertMagicConfig constructs a certmagic.Config for this policy using the
// provided issuers and storage. It encapsulates common logic shared between
// Provision and RebuildCertMagic so we don't duplicate code.
func (ap *AutomationPolicy) makeCertMagicConfig(tlsApp *TLS, issuers []certmagic.Issuer, storage certmagic.Storage) (certmagic.Config, error) {
	// key source
	keyType := ap.KeyType
	if keyType != "" {
		var err error
		keyType, err = caddy.NewReplacer().ReplaceOrErr(ap.KeyType, true, true)
		if err != nil {
			return certmagic.Config{}, fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
		}
		if _, ok := supportedCertKeyTypes[keyType]; !ok {
			return certmagic.Config{}, fmt.Errorf("unrecognized key type: %s", keyType)
		}
	}
	keySource := certmagic.StandardKeyGenerator{
		KeyType: supportedCertKeyTypes[keyType],
	}

	if storage == nil {
		storage = tlsApp.ctx.Storage()
	}

	// on-demand TLS
	var ond *certmagic.OnDemandConfig
	if ap.OnDemand || len(ap.Managers) > 0 {
		// permission module is now required after a number of negligence cases that allowed abuse;
		// but it may still be optional for explicit subjects (bounded, non-wildcard), for the
		// internal issuer since it doesn't cause public PKI pressure on ACME servers; subtly, it
		// is useful to allow on-demand TLS to be enabled so Managers can be used, but to still
		// prevent issuance from Issuers (when Managers don't provide a certificate) if there's no

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Use one of the exact supported values: rsa2048, rsa4096, p256, p384, ed25519 (lowercase).
  2. For ECDSA P-256 (the default) you can simply omit key_type.
  3. Remove any surrounding whitespace or quotes artifacts from the value.

Example fix

# before
example.com {
	tls {
		key_type RSA-2048
	}
}

# after
example.com {
	tls {
		key_type rsa2048
	}
}
Defensive patterns

Strategy: type-guard

Validate before calling

var allowedKeyTypes = map[string]bool{"rsa2048": true, "rsa4096": true, "p256": true, "p384": true, "ed25519": true}
if kt := policy.KeyType; kt != "" && !allowedKeyTypes[kt] {
    return fmt.Errorf("key_type %q invalid; want one of rsa2048, rsa4096, p256, p384, ed25519", kt)
}

Type guard

func isValidKeyType(kt string) bool {
    switch kt {
    case "", "rsa2048", "rsa4096", "p256", "p384", "ed25519":
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Setting key_type (Caddyfile) or "key_type" (JSON) to a string outside the supported set, including wrong casing (matching is case-sensitive) or algorithm-family names like 'ecdsa'/'rsa' without a size.

Common situations: Copy-pasting key type names from OpenSSL configs ('RSA-2048') or other servers; assuming case-insensitivity; using 'P256' instead of 'p256'; using 'rsa2048' vs intending 'rsa4096'.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/a22c630b3b98b621. Report an issue: GitHub.