{"record":{"id":"d479e0fb1c0482e7","repo":"caddyserver/caddy","slug":"s-route-d-matcher-set-d-matcher-d-host-mat","errorCode":null,"errorMessage":"%s: route %d, matcher set %d, matcher %d, host matcher %d: %v","messagePattern":"(.+?): route (.+?), matcher set (.+?), matcher (.+?), host matcher (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/autohttps.go","lineNumber":158,"sourceCode":"\t\t\tlogger.Info(\"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS\",\n\t\t\t\tzap.String(\"server_name\", srvName),\n\t\t\t\tzap.Int(\"https_port\", app.httpsPort()),\n\t\t\t)\n\t\t\tsrv.TLSConnPolicies = caddytls.ConnectionPolicies{new(caddytls.ConnectionPolicy)}\n\t\t}\n\n\t\t// find all qualifying domain names (deduplicated) in this server\n\t\t// (this is where we need the provisioned, decoded request matchers)\n\t\tserverDomainSet := make(map[string]struct{})\n\t\tfor routeIdx, route := range srv.Routes {\n\t\t\tfor matcherSetIdx, matcherSet := range route.MatcherSets {\n\t\t\t\tfor matcherIdx, m := range matcherSet {\n\t\t\t\t\tif hm, ok := m.(*MatchHost); ok {\n\t\t\t\t\t\tfor hostMatcherIdx, d := range *hm {\n\t\t\t\t\t\t\tvar err error\n\t\t\t\t\t\t\td, err = repl.ReplaceOrErr(d, true, false)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"%s: route %d, matcher set %d, matcher %d, host matcher %d: %v\",\n\t\t\t\t\t\t\t\t\tsrvName, routeIdx, matcherSetIdx, matcherIdx, hostMatcherIdx, err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif !slices.Contains(srv.AutoHTTPS.Skip, d) {\n\t\t\t\t\t\t\t\tserverDomainSet[d] = struct{}{}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// build the list of domains that could be used with ECH (if enabled)\n\t\t// so the TLS app can know to publish ECH configs for them\n\t\techDomains := make([]string, 0, len(serverDomainSet))\n\t\tfor d := range serverDomainSet {\n\t\t\techDomains = append(echDomains, d)\n\t\t}\n\t\tapp.tlsApp.RegisterServerNames(echDomains, httpsRRALPNs(srv))","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/autohttps.go#L140-L176","documentation":"Thrown during automatic HTTPS provisioning when a host matcher value in a server's route cannot have placeholders resolved. The HTTP app walks every route's matcher sets, finds MatchHost entries, and calls replacer.ReplaceOrErr(d, true, false); if a placeholder inside a host name errors (e.g. an environment variable placeholder that is unknown or empty with error-on-empty semantics), provisioning aborts with the server name and precise indexes of the offending matcher.","triggerScenarios":"A site block whose host matcher contains a placeholder like {$SITE_NAME} or {env.DOMAIN} that the global replacer cannot resolve at provision time (unset env var, unknown placeholder key, or a placeholder that resolves to empty string). Occurs only when auto-HTTPS runs, i.e. the server has HTTPS-capable addresses and skip_auto_https is not set.","commonSituations":"Running Caddy with a Caddyfile that uses {env.DOMAIN} as the site address but forgetting to export the variable; typos in placeholder names; using custom placeholder sources that are registered after provisioning; deploying the same config to a machine missing the env var.","solutions":["Export the missing environment variable (e.g. `export SITE_NAME=example.com`) or define it in the Caddyfile env block before starting Caddy","Fix the placeholder name to one the global replacer knows (env.* vars must exist at process start)","If the value is optional, give it a default: `{$SITE_NAME:localhost}`","Skip auto-HTTPS for that server (`auto_https off` or skip_auto_https) if you manage certs manually, so host matchers are not resolved this way"],"exampleFix":"# before\n{$SITE_NAME} {\n  respond \"hi\"\n}\n# after (run with the var set, or default it)\n{$SITE_NAME:localhost} {\n  respond \"hi\"\n}","handlingStrategy":"validation","validationCode":"# Caddyfile: verify placeholders resolve before start\nDOMAIN={$SITE_NAME:?SITE_NAME is not set}  # fails fast in shell with message\n# or use a default so resolution can never error:\n# site address: {$SITE_NAME:localhost}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give every host-placeholder a default: {$VAR:fallback}","Export env vars in the unit file / container env before caddy starts","Validate configs with `caddy validate --config Caddyfile` in CI before deploy"],"tags":["caddy","auto-https","placeholders","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}