{"record":{"id":"9c2090a0c89eb972","repo":"caddyserver/caddy","slug":"delimiters-must-consist-of-exactly-two-elements-o","errorCode":null,"errorMessage":"delimiters must consist of exactly two elements: opening and closing","messagePattern":"delimiters must consist of exactly two elements: opening and closing","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/templates/templates.go","lineNumber":433,"sourceCode":"\t\treturn fmt.Errorf(\"loading template extensions: %v\", err)\n\t}\n\tfor _, modIface := range mods.(map[string]any) {\n\t\tt.customFuncs = append(t.customFuncs, modIface.(CustomFunctions).CustomTemplateFunctions())\n\t}\n\n\tif t.MIMETypes == nil {\n\t\tt.MIMETypes = defaultMIMETypes\n\t}\n\tif t.FileRoot == \"\" {\n\t\tt.FileRoot = \"{http.vars.root}\"\n\t}\n\treturn nil\n}\n\n// Validate ensures t has a valid configuration.\nfunc (t *Templates) Validate() error {\n\tif len(t.Delimiters) != 0 && len(t.Delimiters) != 2 {\n\t\treturn fmt.Errorf(\"delimiters must consist of exactly two elements: opening and closing\")\n\t}\n\treturn nil\n}\n\nfunc (t *Templates) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {\n\tbuf := bufPool.Get().(*bytes.Buffer)\n\tbuf.Reset()\n\tdefer bufPool.Put(buf)\n\n\t// shouldBuf determines whether to execute templates on this response,\n\t// since generally we will not want to execute for images or CSS, etc.\n\tshouldBuf := func(status int, header http.Header) bool {\n\t\tct := header.Get(\"Content-Type\")\n\t\tfor _, mt := range t.MIMETypes {\n\t\t\tif strings.Contains(ct, mt) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/templates/templates.go#L415-L451","documentation":"Returned by Templates.Validate when the 'delimiters' field is set but does not have exactly two elements (opening and closing). The check allows only the zero-value (unset) or a two-element array; anything else is rejected at config validation time before serving.","triggerScenarios":"Configuring the templates handler with a delimiters array of length 1, 3, or more; e.g. providing only an opening delimiter like [[[ without a matching ]]], or accidentally listing three strings.","commonSituations":"Hand-editing JSON config where delimiters is an array, copying Go's template syntax expectations into Caddy config, or a Caddyfile like `templates { delimiters [[ ]] }` where a stray token makes three args.","solutions":["Set exactly two delimiters, opening then closing: delimiters [[[ ]]]","Remove the delimiters field entirely to use the defaults {{ and }}","Validate the config before deploying with `caddy validate --config <file>`","Check for accidental extra tokens/args in the Caddyfile block"],"exampleFix":"# before\ntemplates {\n    delimiters [[[ ]]] ]]\n}\n\n# after\ntemplates {\n    delimiters [[[ ]]]\n}","handlingStrategy":"validation","validationCode":"caddy validate --config Caddyfile  # Validate() rejects bad delimiter counts before serving","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always supply delimiters as a pair (open, close)","Run caddy validate in CI to catch structural config errors","Prefer default {{ }} delimiters unless the content genuinely conflicts"],"tags":["caddy","templates","delimiters","configuration"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}