caddyserver/caddy · error
expanding EAB key ID '%s': %v
Error message
expanding EAB key ID '%s': %v
What it means
Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:166) when an External Account Binding key ID (eab key_id / JSON "key_id") contains a placeholder that fails to expand. EAB is required by some ACME CAs (ZeroSSL, Google Trust Services, private CAs); a broken placeholder in the key ID prevents issuer setup entirely.
Source
Thrown at modules/caddytls/acmeissuer.go:166
}
iss.CA = ca
}
// expand TestCA endpoint, if non-empty
if iss.TestCA != "" {
testca, err := repl.ReplaceOrErr(iss.TestCA, true, true)
if err != nil {
return fmt.Errorf("expanding TestCA endpoint '%s': %v", iss.TestCA, err)
}
iss.TestCA = testca
}
// expand EAB credentials, if non-empty
if iss.ExternalAccount != nil {
if iss.ExternalAccount.KeyID != "" {
keyID, err := repl.ReplaceOrErr(iss.ExternalAccount.KeyID, true, true)
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)
}View on GitHub (pinned to 50e54ee279)
Solutions
- Set EAB_KEY_ID in the actual service environment (systemd Environment=, EnvironmentFile=, or container env) and restart/reload Caddy
- Verify with: sudo systemctl show caddy -p Environment or printenv inside the container
- Fix the placeholder to exactly {env.EAB_KEY_ID}; no spaces, balanced braces
- If EAB is not required by your CA, remove the eab block entirely
Example fix
# before
example.com {
tls {
issuer acme {
eab {
key_id {env.EAB_KEYID} # actual var is EAB_KEY_ID
mac_key {env.EAB_MAC_KEY}
}
}
}
}
# after
example.com {
tls {
issuer acme {
eab {
key_id {env.EAB_KEY_ID}
mac_key {env.EAB_MAC_KEY}
}
}
}
}
# systemd: EnvironmentFile=/etc/caddy/acme.env (defines both vars) Defensive patterns
Strategy: validation
Validate before calling
// verify all EAB env vars exist before deploy
for _, k := range []string{"EAB_KEY_ID", "EAB_MAC_KEY"} {
if os.Getenv(k) == "" {
return fmt.Errorf("%s must be set for EAB-enabled ACME issuance", k)
}
} Try / catch
if err := issuer.Provision(ctx); err != nil {
if strings.Contains(err.Error(), "expanding EAB key ID") {
// EAB_KEY_ID missing: add to EnvironmentFile, then reload
}
return err
} Prevention
- Store EAB credentials in a permission-600 EnvironmentFile referenced by the unit
- Secret-check in CI: fail the pipeline when {env.*} references lack values in the deployment environment
- Rotate EAB creds by updating the file and reloading Caddy, never by editing inline literals
When it happens
Trigger: Configuring tls { issuer acme { eab { key_id {env.EAB_KEY_ID} mac_key ... } } } where EAB_KEY_ID is not present in Caddy's environment, or the placeholder expression is malformed.
Common situations: Credentials stored in .env files that the systemd unit or container does not load; rotating EAB credentials in a secret manager but not updating the env var; copying configs to a new host without the secrets; brace typos.
Related errors
- expanding EAB MAC key (redacted): %v
- expanding email address '%s': %v
- expanding CA endpoint '%s': %v
- expanding TestCA endpoint '%s': %v
- expanding account key PEM '%s': %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/fc3df43e533ffeec.
Report an issue: GitHub.