{"record":{"id":"60e908f6c94d9c1f","repo":"caddyserver/caddy","slug":"too-many-for-heredoc-on-line-d-only-use-two","errorCode":null,"errorMessage":"too many '<' for heredoc on line #%d; only use two, for example <<END","messagePattern":"too many '<' for heredoc on line #(.+?); only use two, for example <<END","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"caddyconfig/caddyfile/lexer.go","lineNumber":163,"sourceCode":"\t\t\t}\n\n\t\t\t// skip CR, we only care about LF\n\t\t\tif ch == '\\r' {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// after hitting a newline, we know that the heredoc marker\n\t\t\t// is the characters after the two << and the newline.\n\t\t\t// we reset the val because the heredoc is syntax we don't\n\t\t\t// want to keep.\n\t\t\tif ch == '\\n' {\n\t\t\t\tif len(val) == 2 {\n\t\t\t\t\treturn false, fmt.Errorf(\"missing opening heredoc marker on line #%d; must contain only alphanumeric characters, dashes and underscores; got empty string\", l.line)\n\t\t\t\t}\n\n\t\t\t\t// check if there's too many <\n\t\t\t\tif string(val[:3]) == \"<<<\" {\n\t\t\t\t\treturn false, fmt.Errorf(\"too many '<' for heredoc on line #%d; only use two, for example <<END\", l.line)\n\t\t\t\t}\n\n\t\t\t\theredocMarker = string(val[2:])\n\t\t\t\tif !heredocMarkerRegexp.Match([]byte(heredocMarker)) {\n\t\t\t\t\treturn false, fmt.Errorf(\"heredoc marker on line #%d must contain only alphanumeric characters, dashes and underscores; got '%s'\", l.line, heredocMarker)\n\t\t\t\t}\n\n\t\t\t\tinHeredoc = true\n\t\t\t\tl.skippedLines++\n\t\t\t\tval = nil\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tval = append(val, ch)\n\t\t\tcontinue\n\t\t}\n\n\t\t// if we're in a heredoc, all characters are read as-is\n\t\tif inHeredoc {","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddyconfig/caddyfile/lexer.go#L145-L181","documentation":"The heredoc opener used three or more '<' characters (e.g. <<<EOF). Caddy heredocs use exactly two: <<MARKER. Three-angle heredocs are a bash-ism ('here-string') that Caddy does not support.","triggerScenarios":"A Caddyfile line contains '<<<' before the marker on the opening heredoc line; the lexer detects val[:3] == \"<<<\" when the newline arrives.","commonSituations":"Copy-pasting shell scripts or examples that use <<< into a Caddyfile directive, or muscle memory from bash here-strings.","solutions":["Change <<<MARKER to <<MARKER","If a here-string was intended, inline the value directly as a normal argument instead"],"exampleFix":"# before\nrespond <<<EOF\n# after\nrespond <<EOF","handlingStrategy":"validation","validationCode":"if strings.Contains(line, \"<<<\") {\n    return fmt.Errorf(\"three-angle heredoc not supported: %q\", line)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use exactly two '<' for heredocs","Don't paste shell here-strings into Caddyfiles"],"tags":["caddyfile","heredoc","lexer"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}