crowdsecurity/crowdsec · error
missing '%s' header
Error message
missing '%s' header
What it means
NewParsedRequestFromRequest builds a ParsedRequest from the internal HTTP request the bouncer forwards, which must carry X-Crowdsec-Appsec-IP (IPHeaderName) identifying the original client. This error means that required header is absent, so the client IP is unknown and the request cannot be evaluated.
Source
Thrown at pkg/appsec/request.go:407
ip := net.ParseIP(host)
if ip == nil {
log.Errorf("Invalid appsec remote IP address source %v", remoteAddr)
return remoteAddr
}
return ip.String()
}
// Generate a ParsedRequest from a http.Request. ParsedRequest can be consumed by the App security Engine.
// bodySettings controls the maximum body size and what to do when the limit is exceeded.
func NewParsedRequestFromRequest(r *http.Request, logger *log.Entry, bodySettings BodySettings) (ParsedRequest, error) {
body, bodyTruncated, bodySizeExceeded, err := readRequestBody(r, bodySettings, logger)
if err != nil {
return ParsedRequest{}, err
}
clientIP := r.Header.Get(IPHeaderName)
if clientIP == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", IPHeaderName)
}
clientURI := r.Header.Get(URIHeaderName)
if clientURI == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", URIHeaderName)
}
clientMethod := r.Header.Get(VerbHeaderName)
if clientMethod == "" {
return ParsedRequest{}, fmt.Errorf("missing '%s' header", VerbHeaderName)
}
clientHost := r.Header.Get(HostHeaderName)
if clientHost == "" {
logger.Debugf("missing '%s' header", HostHeaderName)
}
userAgent := r.Header.Get(UserAgentHeaderName)View on GitHub (pinned to 909b515798)
Solutions
- Update/configure your bouncer to send the X-Crowdsec-Appsec-IP header on forwarded requests
- Verify no proxy in between strips X-Crowdsec-* headers
- Ensure requests reach the appsec endpoint only via the bouncer, not directly
- Check bouncer/crowdsec version compatibility (appsec header protocol)
Example fix
// bouncer side: before
req, _ := http.NewRequest("POST", appsecURL, body)
// after
req.Header.Set("X-Crowdsec-Appsec-IP", clientIP)
req.Header.Set("X-Crowdsec-Appsec-URI", uri)
req.Header.Set("X-Crowdsec-Appsec-Verb", method)
req.Header.Set("X-Crowdsec-Appsec-Host", host) Defensive patterns
Strategy: validation
Validate before calling
if r.Header.Get("X-Crowdsec-Appsec-IP") == "" {
// don't call NewParsedRequestFromRequest; reject or skip appsec
} Try / catch
pr, _, _, err := NewParsedRequestFromRequest(r, logger)
if err != nil {
log.Errorf("malformed appsec request: %v", err)
http.Error(w, "bad request", http.StatusBadRequest)
return
} Prevention
- Always route appsec traffic through a bouncer that sets the full header set
- Add integration tests asserting X-Crowdsec-Appsec-* headers are present
- Check proxies don't strip X- headers
When it happens
Trigger: appsecHandler (or tests) calls NewParsedRequestFromRequest on a request whose IPHeaderName header is missing or empty — usually a misconfigured bouncer or a direct request hitting the appsec endpoint bypassing the bouncer.
Common situations: Bouncer not configured to forward X-Crowdsec-Appsec-* headers, older bouncer version predating the header set, direct curl/browser access to the appsec port, or a proxy stripping custom headers.
Related errors
- headers is selected, but headers is not provided
- invalid schema name
- multiple Authorization headers found
- ref cannot be empty
- on_challenge_submit hooks are only valid in-band, not under
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/7420c289f8b2f769.
Report an issue: GitHub.