{"record":{"id":"420079dc4a83acf3","repo":"caddyserver/caddy","slug":"evaluated-placeholder-s-s-s-is-empty","errorCode":null,"errorMessage":"evaluated placeholder %s%s%s is empty","messagePattern":"evaluated placeholder (.+?)(.+?)(.+?) is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replacer.go","lineNumber":269,"sourceCode":"\t\t}\n\n\t\t// apply any transformations\n\t\tif f != nil {\n\t\t\tvar err error\n\t\t\tval, err = f(key, val)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t}\n\n\t\t// convert val to a string as efficiently as possible\n\t\tvalStr := ToString(val)\n\n\t\t// write the value; if it's empty, either return\n\t\t// an error or write a default value\n\t\tif valStr == \"\" {\n\t\t\tif errOnEmpty {\n\t\t\t\treturn \"\", fmt.Errorf(\"evaluated placeholder %s%s%s is empty\",\n\t\t\t\t\tstring(phOpen), key, string(phClose))\n\t\t\t} else if empty != \"\" {\n\t\t\t\tsb.WriteString(empty)\n\t\t\t}\n\t\t} else {\n\t\t\tsb.WriteString(valStr)\n\t\t}\n\n\t\t// advance cursor to end of placeholder\n\t\ti = end\n\t\tlastWriteCursor = i + 1\n\t}\n\n\t// flush any unwritten remainder\n\tsb.WriteString(input[lastWriteCursor:])\n\n\treturn sb.String(), nil\n}","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/replacer.go#L251-L287","documentation":"In errOnEmpty mode (ReplaceOrErr with errorOnEmpty), the replacer treats a placeholder that resolves to an empty string as a failure and returns this error naming the placeholder. This is stricter than unknown-key handling: the key was found, but its value is empty, which strict consumers (like dial addresses) consider invalid.","triggerScenarios":"ReplaceOrErr(input, true, true) where a known placeholder expands to \"\" — e.g. {$EMPTY_VAR} where EMPTY_VAR is exported but set to nothing, feeding output net's address.","commonSituations":"Environment variables defined but blank (trailing whitespace, empty assignments in .env files); default values not configured for optional variables used in strict config fields.","solutions":["Give the variable a non-empty value, or use Caddy's placeholder default syntax {$VAR:fallback}","Unset the variable entirely if the placeholder should be removed rather than blank","Move the value out of a strict substituted field if empty is legitimately acceptable"],"exampleFix":"# before\noutput net {$LOG_ENDPOINT} # LOG_ENDPOINT=\"\"\n\n# after\noutput net {$LOG_ENDPOINT:127.0.0.1:514}","handlingStrategy":"validation","validationCode":"if v := os.Getenv(\"LOG_ENDPOINT\"); v == \"\" {\n    return fmt.Errorf(\"LOG_ENDPOINT resolves to empty\")\n}","typeGuard":null,"tryCatchPattern":"if out, err := repl.ReplaceOrErr(in, true, true); err != nil {\n    if strings.HasPrefix(err.Error(), \"evaluated placeholder\") && strings.HasSuffix(err.Error(), \"is empty\") {\n        // supply a default and retry\n    }\n}","preventionTips":["Use {$VAR:fallback} defaults in strict fields","Fail fast at startup on blank env vars rather than at substitution"],"tags":["caddy","replacer","placeholders","environment"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}