{"record":{"id":"d2c6668fa969905a","repo":"caddyserver/caddy","slug":"expanding-ca-endpoint-s-v","errorCode":null,"errorMessage":"expanding CA endpoint '%s': %v","messagePattern":"expanding CA endpoint '(.+?)': (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/acmeissuer.go","lineNumber":147,"sourceCode":"func (iss *ACMEIssuer) Provision(ctx caddy.Context) error {\n\tiss.logger = ctx.Logger()\n\n\trepl := caddy.NewReplacer()\n\n\t// expand email address, if non-empty\n\tif iss.Email != \"\" {\n\t\temail, err := repl.ReplaceOrErr(iss.Email, true, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expanding email address '%s': %v\", iss.Email, err)\n\t\t}\n\t\tiss.Email = email\n\t}\n\n\t// expand CA endpoint, if non-empty\n\tif iss.CA != \"\" {\n\t\tca, err := repl.ReplaceOrErr(iss.CA, true, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expanding CA endpoint '%s': %v\", iss.CA, err)\n\t\t}\n\t\tiss.CA = ca\n\t}\n\n\t// expand TestCA endpoint, if non-empty\n\tif iss.TestCA != \"\" {\n\t\ttestca, err := repl.ReplaceOrErr(iss.TestCA, true, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expanding TestCA endpoint '%s': %v\", iss.TestCA, err)\n\t\t}\n\t\tiss.TestCA = testca\n\t}\n\n\t// expand EAB credentials, if non-empty\n\tif iss.ExternalAccount != nil {\n\t\tif iss.ExternalAccount.KeyID != \"\" {\n\t\t\tkeyID, err := repl.ReplaceOrErr(iss.ExternalAccount.KeyID, true, true)\n\t\t\tif err != nil {","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/acmeissuer.go#L129-L165","documentation":"Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:147) when the ACME directory endpoint field contains a placeholder that fails to expand. Because the replacer treats unresolved placeholders as errors, an unknown env var or malformed expression in the acme_ca URL aborts provisioning of the issuer.","triggerScenarios":"Configuring acme_ca (or the JSON issuer's \"ca\") with a placeholder such as {env.ACME_DIRECTORY_URL} that resolves to nothing, or with invalid placeholder syntax; also custom shorthands not registered in the replacer.","commonSituations":"Pointing at a private ACME server (step-ca, smallstep, Vault) via env var that is missing in the systemd unit or container; renaming the variable in CI but not in the Caddy config; extra spaces inside braces like { env.URL }.","solutions":["Export the variable in the service environment (Environment=ACME_DIRECTORY_URL=... in the unit, or env: in compose) and restart Caddy","Correct the placeholder spelling/braces - it must be exactly {env.VAR}","If the endpoint is fixed, write the literal URL (e.g. https://acme.example.com/directory) and remove the placeholder","Validate config early: caddy validate --config Caddyfile"],"exampleFix":"# before\n{\n  acme_ca {env.ACME_DIRECTORY}   # variable name is ACME_DIRECTORY_URL\n}\n\n# after\n{\n  acme_ca {env.ACME_DIRECTORY_URL}\n}\n# compose:\n#   environment:\n#     - ACME_DIRECTORY_URL=https://acme.internal/dir","handlingStrategy":"validation","validationCode":"// fail fast if the ACME directory env var is missing\nif os.Getenv(\"ACME_DIRECTORY_URL\") == \"\" && strings.Contains(cfgText, \"{env.ACME_DIRECTORY_URL}\") {\n    return errors.New(\"ACME_DIRECTORY_URL must be set before starting Caddy\")\n}","typeGuard":null,"tryCatchPattern":"if err := issuer.Provision(ctx); err != nil {\n    if strings.Contains(err.Error(), \"expanding CA endpoint\") {\n        // env var missing or placeholder typo: set it in the unit/compose and reload\n    }\n    return err\n}","preventionTips":["Keep private ACME endpoints in one variable used by both CI and the service unit","Use literal URLs for stable endpoints; reserve placeholders for values that truly vary per host","Add caddy validate to the deploy pipeline run with the same env"],"tags":["tls","acme","placeholders","environment","ca-endpoint"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}