caddyserver/caddy · error

%s: entry %q has '*' in an invalid position (only a trailing

Error message

%s: entry %q has '*' in an invalid position (only a trailing '*' is allowed)

What it means

Header alias allowlist entries support only a single trailing '*' as a wildcard. This error fires when '*' appears anywhere else in the name (after trimming a trailing '*'), e.g. a leading or middle asterisk. Such patterns are not supported by the precomputed exact/prefix matching structures the filter builds.

Source

Thrown at modules/caddyhttp/server.go:406

	for _, entry := range entries {
		// Reject non-ASCII bytes: Go's HTTP parser returns 400 for
		// non-ASCII header names, so such entries can never match.
		for i := 0; i < len(entry); i++ {
			if entry[i] >= 0x80 {
				return nil, nil, nil, fmt.Errorf("%s: entry %q contains non-ASCII characters", directive, entry)
			}
		}

		isGlob := strings.HasSuffix(entry, "*")
		name := entry
		if isGlob {
			name = strings.TrimSuffix(entry, "*")
		}

		// Reject entries with '*' not at the trailing position.
		if strings.ContainsRune(name, '*') {
			return nil, nil, nil, fmt.Errorf("%s: entry %q has '*' in an invalid position (only a trailing '*' is allowed)", directive, entry)
		}

		// The name (without trailing '*') must contain at least one separator.
		if !strings.ContainsRune(name, sep) {
			return nil, nil, nil, fmt.Errorf("%s: entry %q does not contain a %q", directive, entry, sep)
		}

		canonAllow := http.CanonicalHeaderKey(name)
		canonDrop := http.CanonicalHeaderKey(strings.ReplaceAll(name, string(sep), "-"))

		if isGlob {
			prefixRules = append(prefixRules, aliasPrefixRule{
				allow: canonAllow,
				drop:  canonDrop,
			})
		} else {
			exactAllow[canonAllow] = struct{}{}
			exactDrop[canonDrop] = struct{}{}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Move the wildcard to the end: use "prefix*" not "*suffix" or "a*b"
  2. For leading-wildcard needs, enumerate explicit entries instead
  3. Re-validate the config after the change

Example fix

// before
"-": ["*api.internal"]

// after
"-": ["x_api.internal", "stage-x_api*"]
Defensive patterns

Strategy: validation

Validate before calling

func validWildcard(entry string) error {
    name := strings.TrimSuffix(entry, "*")
    if strings.ContainsRune(name, '*') {
        return fmt.Errorf("%q: '*' only allowed as trailing character", entry)
    }
    return nil
}

Prevention

When it happens

Trigger: An allowlist entry like "*api.example.com" or "X-*Api*" in the header alias config; only "X_Api*" style trailing globs are legal.

Common situations: Assuming full glob/fnmatch semantics when writing allowlist entries; porting wildcard patterns from other proxies.

Related errors


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