{"record":{"id":"7d33bff965d95f0e","repo":"caddyserver/caddy","slug":"automation-policy-d-is-the-second-policy-that-act","errorCode":null,"errorMessage":"automation policy %d is the second policy that acts as default/catch-all, but will never be used","messagePattern":"automation policy (.+?) is the second policy that acts as default/catch-all, but will never be used","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/tls.go","lineNumber":380,"sourceCode":"\t\t}\n\t}\n\n\treturn nil\n}\n\n// Validate validates t's configuration.\nfunc (t *TLS) Validate() error {\n\tif t.Automation != nil {\n\t\t// ensure that host aren't repeated; since only the first\n\t\t// automation policy is used, repeating a host in the lists\n\t\t// isn't useful and is probably a mistake; same for two\n\t\t// catch-all/default policies\n\t\tvar hasDefault bool\n\t\thostSet := make(map[string]int)\n\t\tfor i, ap := range t.Automation.Policies {\n\t\t\tif len(ap.subjects) == 0 {\n\t\t\t\tif hasDefault {\n\t\t\t\t\treturn fmt.Errorf(\"automation policy %d is the second policy that acts as default/catch-all, but will never be used\", i)\n\t\t\t\t}\n\t\t\t\thasDefault = true\n\t\t\t}\n\t\t\tfor _, h := range ap.subjects {\n\t\t\t\tif first, ok := hostSet[h]; ok {\n\t\t\t\t\treturn fmt.Errorf(\"automation policy %d: cannot apply more than one automation policy to host: %s (first match in policy %d)\", i, h, first)\n\t\t\t\t}\n\t\t\t\thostSet[h] = i\n\t\t\t}\n\t\t}\n\t}\n\tif t.Cache != nil {\n\t\tif t.Cache.Capacity < 0 {\n\t\t\treturn fmt.Errorf(\"cache capacity must be >= 0\")\n\t\t}\n\t}\n\treturn nil\n}","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/tls.go#L362-L398","documentation":"During TLS app validation, Caddy enforces that at most one automation policy may have an empty subject list (the default/catch-all policy), because policy matching is first-match-wins: a second catch-all is dead configuration that can never apply. This error fires when two or more policies in automation.policies have no subjects.","triggerScenarios":"automation.policies containing e.g. [{issuers: A}, {subjects: [\"x.com\"]}, {issuers: B}] — both the first and third entries are subject-less; the third (index reported as %d) is unreachable.","commonSituations":"Appending a global policy for a new issuer without realizing an earlier policy already acts as default; merging configs that each had their own default policy; ordering mistakes where a specific policy was meant to be global and vice versa.","solutions":["Give all but one policy explicit subjects","Or delete the redundant catch-all policy (index in the message) and merge its settings into the single default","Remember order matters: place specific-subject policies before the catch-all"],"exampleFix":"// before\n\"policies\": [\n  {\"issuers\": [{\"module\": \"acme\"}]},\n  {\"subjects\": [\"example.com\"]},\n  {\"issuers\": [{\"module\": \"internal\"}]}\n]\n// after\n\"policies\": [\n  {\"subjects\": [\"example.com\"], \"issuers\": [{\"module\": \"internal\"}]},\n  {\"issuers\": [{\"module\": \"acme\"}]}\n]","handlingStrategy":"validation","validationCode":"catchAlls := 0\nfor i, p := range tlsApp.Automation.Policies {\n\tif len(p.SubjectsRaw) == 0 {\n\t\tcatchAlls++\n\t\tif catchAlls > 1 {\n\t\t\treturn fmt.Errorf(\"policy %d is a redundant catch-all\", i)\n\t\t}\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Design policies with exactly one default (no subjects) and all others with explicit subjects","Put the catch-all policy last"],"tags":["caddy","tls","automation-policy","validation","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}