caddyserver/caddy · error
%s: entry %q does not contain a %q
Error message
%s: entry %q does not contain a %q
What it means
Each header alias allowlist entry (after removing a trailing '*') must contain at least one separator character — '_' or '.', depending on the directive — because the alias mechanism works by rewriting that separator to/from '-' in header names. Entries without a separator are rejected at provisioning with the required separator shown via %q.
Source
Thrown at modules/caddyhttp/server.go:411
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{}{}
}
}
return exactAllow, exactDrop, prefixRules, nil
}View on GitHub (pinned to 50e54ee279)
Solutions
- Add the required separator to the header name so an alias actually exists
- Remove entries that name headers without separators — they cannot be aliased
- Check the %q in the message to confirm which separator ('_' or '.') the directive expects
Example fix
// before "-": ["XApiKey"] // after "-": ["X_Api_Key"]
Defensive patterns
Strategy: validation
Validate before calling
func hasSeparator(entries []string, sep rune) error {
for _, e := range entries {
name := strings.TrimSuffix(e, "*")
if !strings.ContainsRune(name, sep) {
return fmt.Errorf("entry %q lacks required %q separator", e, sep)
}
}
return nil
} Prevention
- Understand the feature aliases '_'/'.' to '-', so only names with separators belong in the list
- Read the directive's %q output to confirm which separator is required
When it happens
Trigger: An entry like "XApiKey" or "xapi" with no '_' or '.'; only names such as "X_Api_Key" or "x.api.key" are meaningful aliases.
Common situations: Listing ordinary header names (no separator) in the alias allowlist, misunderstanding that the feature targets underscore/dot-to-dash canonicalization.
Related errors
- replacement %d for header field '%s': %v
- cannot specify both a substring search and a regular express
- %s: entry %q contains non-ASCII characters
- %s: entry %q has '*' in an invalid position (only a trailing
- server %s: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/815fb48b3164c625.
Report an issue: GitHub.