caddyserver/caddy · error

unrecognized placeholder %s%s%s

Error message

unrecognized placeholder %s%s%s

What it means

When the replacer runs in errOnUnknown mode (ReplaceOrErr with errorOnUnknown, used e.g. for net writer addresses and other strict contexts) and encounters a {key} that no provider in the replacer recognizes, it fails immediately with the literal placeholder in the message. Non-strict contexts would leave the placeholder untouched instead.

Source

Thrown at replacer.go:243

			if nextEnd < 0 {
				unclosedCount++
				continue scan
			}
			end += nextEnd + 1
		}

		// write the substring from the last cursor to this point
		sb.WriteString(input[lastWriteCursor:i])

		// trim opening bracket
		key := input[i+1 : end]

		// try to get a value for this key, handle empty values accordingly
		val, found := r.Get(key)
		if !found {
			// placeholder is unknown (unrecognized); handle accordingly
			if errOnUnknown {
				return "", fmt.Errorf("unrecognized placeholder %s%s%s",
					string(phOpen), key, string(phClose))
			} else if !treatUnknownAsEmpty {
				// if treatUnknownAsEmpty is true, we'll handle an empty
				// val later; so only continue otherwise
				lastWriteCursor = i
				continue
			}
		}

		// apply any transformations
		if f != nil {
			var err error
			val, err = f(key, val)
			if err != nil {
				return "", err
			}
		}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Fix the placeholder name or define the variable (export it, or add it to the Caddyfile env block)
  2. Use the correct prefix/scope: {$ENV_VAR} for environment, {http.request...} only in request-scoped contexts
  3. Remove the placeholder if a literal value is acceptable

Example fix

# before
output net {$SYSLOGG_HOST}:514 # typo: double G

# after
output net {$SYSLOG_HOST}:514
Defensive patterns

Strategy: validation

Validate before calling

if !repl.KnownReplacement(key) { /* caddy.Replacer: probe first */
    return fmt.Errorf("placeholder %s is not defined at this stage", key)
}

Try / catch

if out, err := repl.ReplaceOrErr(in, true, true); err != nil {
    if strings.HasPrefix(err.Error(), "unrecognized placeholder") {
        // fix or define the placeholder, then retry
    }
    return out, err
}

Prevention

When it happens

Trigger: Calling replacer.ReplaceOrErr(input, true, true) where input contains an unknown placeholder like {not_a_var}; or config fields that Caddy substitutes strictly (e.g. output net address) referencing undefined env vars or placeholders.

Common situations: Typos in placeholder names ({env.FOO} vs {$FOO} confusion); env vars not present in the service environment; using HTTP placeholder names at provisioning time when they only exist at request time.

Related errors


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