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 the

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Set the referenced environment variable (e.g. KEY_TYPE=p256) in the service environment and reload Caddy.
  2. Or replace the placeholder with a literal key type: rsa2048, rsa4096, p256, p384, or ed25519.
  3. 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

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


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