caddyserver/caddy · error
expanding account key PEM '%s': %v
Error message
expanding account key PEM '%s': %v
What it means
Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:183) when the ACME account key PEM field (JSON "account_key", a full private key embedded in config) contains a placeholder that fails to expand. Caddy allows the account key to be supplied via placeholders (e.g. {env.ACME_ACCOUNT_KEY} or a file read via {http...}/{file...} style replacements), and an unresolvable one is a hard error.
Source
Thrown at modules/caddytls/acmeissuer.go:183
if err != nil {
return fmt.Errorf("expanding EAB key ID '%s': %v", iss.ExternalAccount.KeyID, err)
}
iss.ExternalAccount.KeyID = keyID
}
if iss.ExternalAccount.MACKey != "" {
macKey, err := repl.ReplaceOrErr(iss.ExternalAccount.MACKey, true, true)
if err != nil {
return fmt.Errorf("expanding EAB MAC key (redacted): %v", err)
}
iss.ExternalAccount.MACKey = macKey
}
}
// expand account key, if non-empty
if iss.AccountKey != "" {
accountKey, err := repl.ReplaceOrErr(iss.AccountKey, true, true)
if err != nil {
return fmt.Errorf("expanding account key PEM '%s': %v", iss.AccountKey, err)
}
iss.AccountKey = accountKey
}
// expand DNS override domain, if non-empty
if iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.OverrideDomain != "" {
overrideDomain, err := repl.ReplaceOrErr(iss.Challenges.DNS.OverrideDomain, true, true)
if err != nil {
return fmt.Errorf("expanding DNS override domain '%s': %v", iss.Challenges.DNS.OverrideDomain, err)
}
iss.Challenges.DNS.OverrideDomain = overrideDomain
}
// DNS challenge provider, if not already established
if iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.solver == nil {
var prov certmagic.DNSProvider
if iss.Challenges.DNS.ProviderRaw != nil {
// a challenge provider has been locally configured - use itView on GitHub (pinned to 50e54ee279)
Solutions
- Ensure the env var/secret holding the PEM exists on every node running Caddy and restart/reload
- Verify the var contains a valid single-line-escaped or raw PEM that certmagic can decode after expansion; test: printenv ACCOUNT_KEY_PEM | openssl pkey -noout
- Fix placeholder syntax to exactly {env.VAR}
- If you do not need a pinned account key, remove the field - Caddy/certmagic will generate and persist one in storage
Example fix
// before
"issuer": {
"module": "acme",
"account_key": "{env.ACCT_KEY}" // ACCT_KEY unset
}
// after
"issuer": {
"module": "acme"
}
// let certmagic manage the account key in storage, or set ACCT_KEY to the PEM in the service env Defensive patterns
Strategy: validation
Validate before calling
// if pinning an account key, verify the env var holds a parseable PEM first
if v := os.Getenv("ACCT_KEY"); v != "" {
if _, err := certmagic.PEMDecodePrivateKey([]byte(v)); err != nil {
return fmt.Errorf("ACCT_KEY is not a valid private key PEM: %v", err)
}
} else if strings.Contains(cfgText, "{env.ACCT_KEY}") {
return errors.New("ACCT_KEY referenced but not set")
} Try / catch
if err := issuer.Provision(ctx); err != nil {
if strings.Contains(err.Error(), "expanding account key PEM") {
// account key placeholder unresolved: set env var or drop the field
}
return err
} Prevention
- Prefer letting certmagic manage the account key in storage unless you need cross-node account sharing
- If pinning, distribute the key via secrets, and validate it parses (openssl pkey -noout) on each node
- Ensure multi-line PEMs survive transport (base64-wrap if your env layer strips newlines)
When it happens
Trigger: Setting "account_key": "{env.ACCOUNT_KEY_PEM}" on an ACME issuer where the environment variable is missing, or where the placeholder is misspelled; the error occurs even though the raw PEM is never echoed (the message includes iss.AccountKey, i.e. the unexpanded placeholder text, not a secret value, when the placeholder itself is the configured string).
Common situations: Pinning a pre-created ACME account across restarts/clusters by injecting its key via env or secrets; var present on the old node but not on new nodes during scaling; multi-line PEM stored in env vars mangled by YAML/compose folding.
Related errors
- expanding EAB key ID '%s': %v
- expanding EAB MAC key (redacted): %v
- expanding email address '%s': %v
- expanding CA endpoint '%s': %v
- expanding TestCA endpoint '%s': %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/eb78f5707e9e637d.
Report an issue: GitHub.