{"record":{"id":"6d2ae2437f7555d4","repo":"caddyserver/caddy","slug":"unrecognized-placeholder-s-s-s","errorCode":null,"errorMessage":"unrecognized placeholder %s%s%s","messagePattern":"unrecognized placeholder (.+?)(.+?)(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replacer.go","lineNumber":243,"sourceCode":"\t\t\tif nextEnd < 0 {\n\t\t\t\tunclosedCount++\n\t\t\t\tcontinue scan\n\t\t\t}\n\t\t\tend += nextEnd + 1\n\t\t}\n\n\t\t// write the substring from the last cursor to this point\n\t\tsb.WriteString(input[lastWriteCursor:i])\n\n\t\t// trim opening bracket\n\t\tkey := input[i+1 : end]\n\n\t\t// try to get a value for this key, handle empty values accordingly\n\t\tval, found := r.Get(key)\n\t\tif !found {\n\t\t\t// placeholder is unknown (unrecognized); handle accordingly\n\t\t\tif errOnUnknown {\n\t\t\t\treturn \"\", fmt.Errorf(\"unrecognized placeholder %s%s%s\",\n\t\t\t\t\tstring(phOpen), key, string(phClose))\n\t\t\t} else if !treatUnknownAsEmpty {\n\t\t\t\t// if treatUnknownAsEmpty is true, we'll handle an empty\n\t\t\t\t// val later; so only continue otherwise\n\t\t\t\tlastWriteCursor = i\n\t\t\t\tcontinue\n\t\t\t}\n\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","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/replacer.go#L225-L261","documentation":"When the replacer runs in errOnUnknown mode (ReplaceOrErr with errorOnUnknown, used e.g. for net writer addresses and other strict contexts) and encounters a {key} that no provider in the replacer recognizes, it fails immediately with the literal placeholder in the message. Non-strict contexts would leave the placeholder untouched instead.","triggerScenarios":"Calling replacer.ReplaceOrErr(input, true, true) where input contains an unknown placeholder like {not_a_var}; or config fields that Caddy substitutes strictly (e.g. output net address) referencing undefined env vars or placeholders.","commonSituations":"Typos in placeholder names ({env.FOO} vs {$FOO} confusion); env vars not present in the service environment; using HTTP placeholder names at provisioning time when they only exist at request time.","solutions":["Fix the placeholder name or define the variable (export it, or add it to the Caddyfile env block)","Use the correct prefix/scope: {$ENV_VAR} for environment, {http.request...} only in request-scoped contexts","Remove the placeholder if a literal value is acceptable"],"exampleFix":"# before\noutput net {$SYSLOGG_HOST}:514 # typo: double G\n\n# after\noutput net {$SYSLOG_HOST}:514","handlingStrategy":"validation","validationCode":"if !repl.KnownReplacement(key) { /* caddy.Replacer: probe first */\n    return fmt.Errorf(\"placeholder %s is not defined at this stage\", key)\n}","typeGuard":null,"tryCatchPattern":"if out, err := repl.ReplaceOrErr(in, true, true); err != nil {\n    if strings.HasPrefix(err.Error(), \"unrecognized placeholder\") {\n        // fix or define the placeholder, then retry\n    }\n    return out, err\n}","preventionTips":["Use {$VAR} for env vars and request-scoped names only at request time","Prefer {$VAR:default} so substitution never depends on unset state"],"tags":["caddy","replacer","placeholders","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}