caddyserver/caddy · error

missing opening heredoc marker on line #%d; must contain onl

Error message

missing opening heredoc marker on line #%d; must contain only alphanumeric characters, dashes and underscores; got empty string

What it means

The lexer saw '<<' followed immediately by a newline: the heredoc opening marker is empty. The marker name (the characters between << and end of line) is required and must be alphanumeric/dash/underscore.

Source

Thrown at caddyconfig/caddyfile/lexer.go:158

		if (!quoted && !btQuoted) && (!inHeredoc && !heredocEscaped) &&
			len(val) > 1 && string(val[:2]) == "<<" {
			// a space means it's just a regular token and not a heredoc
			if ch == ' ' {
				return makeToken(0), nil
			}

			// skip CR, we only care about LF
			if ch == '\r' {
				continue
			}

			// after hitting a newline, we know that the heredoc marker
			// is the characters after the two << and the newline.
			// we reset the val because the heredoc is syntax we don't
			// want to keep.
			if ch == '\n' {
				if len(val) == 2 {
					return false, fmt.Errorf("missing opening heredoc marker on line #%d; must contain only alphanumeric characters, dashes and underscores; got empty string", l.line)
				}

				// check if there's too many <
				if string(val[:3]) == "<<<" {
					return false, fmt.Errorf("too many '<' for heredoc on line #%d; only use two, for example <<END", l.line)
				}

				heredocMarker = string(val[2:])
				if !heredocMarkerRegexp.Match([]byte(heredocMarker)) {
					return false, fmt.Errorf("heredoc marker on line #%d must contain only alphanumeric characters, dashes and underscores; got '%s'", l.line, heredocMarker)
				}

				inHeredoc = true
				l.skippedLines++
				val = nil
				continue
			}
			val = append(val, ch)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Add a marker name right after << on the same line (e.g. <<EOF)
  2. Close the heredoc with a matching line containing only the marker
  3. Check templating that generates the Caddyfile for empty substitutions

Example fix

# before
respond <<
  hi
EOF
# after
respond <<EOF
  hi
EOF
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasSuffix(line, "<<") {
    return fmt.Errorf("empty heredoc marker on %q", line)
}

Prevention

When it happens

Trigger: A line ends with just '<<' — e.g. 'respond <<' with the marker forgotten, or a template placeholder accidentally left in a Caddyfile.

Common situations: Forgetting to name the marker after <<, or envsubst/template rendering that consumed the marker text, leaving bare '<<' at end of line.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/4be1b97096ec46f3. Report an issue: GitHub.