caddyserver/caddy · error
invalid key type %s: %s
Error message
invalid key type %s: %s
What it means
The automation policy's key_type field is run through Caddy's placeholder replacer (ReplaceOrErr with error-on-empty and error-on-unknown) and the replacement itself failed. This means key_type contained a placeholder like {$KEY_TYPE} or {env.KEY_TYPE} that is either unset (expanded to empty) or not a recognized placeholder.
Source
Thrown at modules/caddytls/automation.go:279
if annoying, ok := issuer.(ConfigSetter); ok {
annoying.SetConfig(ap.magic)
}
}
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 theView on GitHub (pinned to 50e54ee279)
Solutions
- Set the referenced environment variable (e.g. KEY_TYPE=p256) in the service environment and reload Caddy.
- Or replace the placeholder with a literal key type: rsa2048, rsa4096, p256, p384, or ed25519.
- If the placeholder should be optional, remove it from key_type and rely on the default (p256/ECDSA via certmagic defaults).
Example fix
# before
example.com {
tls {
key_type {$KEY_TYPE}
}
}
# KEY_TYPE unset
# after
export KEY_TYPE=p256 # in the caddy service environment
# or hardcode:
tls {
key_type p256
} Defensive patterns
Strategy: validation
Validate before calling
// Reject key types that reference unset placeholders before provisioning.
if strings.Contains(policy.KeyType, "{") {
if v, err := caddy.NewReplacer().ReplaceOrErr(policy.KeyType, true, true); err != nil || v == "" {
return fmt.Errorf("key_type placeholder %q unresolved", policy.KeyType)
}
} Prevention
- Document required env vars per deployment and assert them in startup scripts.
- Avoid placeholders in key_type unless the value is guaranteed present.
When it happens
Trigger: Setting key_type to a placeholder whose environment variable is undefined at config-load time, or using {foo.bar} syntax for a placeholder that does not exist while hard-on-unknown replacement is enabled.
Common situations: Templated configs meant to be parameterized by env vars where the variable was forgotten in systemd unit/container env; moving a config between machines with different env setups.
Related errors
- expanding email address '%s': %v
- expanding CA endpoint '%s': %v
- expanding TestCA endpoint '%s': %v
- expanding EAB key ID '%s': %v
- expanding EAB MAC key (redacted): %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/07a03d1d104eac7d.
Report an issue: GitHub.