crowdsecurity/crowdsec · error
unexpected status code: %d
Error message
unexpected status code: %d
What it means
The longpollclient's poll() performs a streaming HTTP request to the LAPI (or other endpoint) and expects a 200 response before decoding the JSON stream. If the response carries any other status code, it returns 'unexpected status code: %d'. 401 responses are special-cased into errUnauthorized earlier in the function, so any other non-200 (403, 404, 500, 502…) surfaces through this error, aborting the poll loop.
Source
Thrown at pkg/longpollclient/client.go:106
return err
}
defer resp.Body.Close()
requestId := resp.Header.Get("X-Amzn-Trace-Id")
logger = logger.WithField("request-id", requestId)
if resp.StatusCode != http.StatusOK {
c.logger.Errorf("unexpected status code: %d", resp.StatusCode)
if resp.StatusCode == http.StatusPaymentRequired {
bodyContent, err := io.ReadAll(resp.Body)
if err != nil {
logger.Errorf("failed to read response body: %s", err)
return err
}
logger.Error(string(bodyContent))
return errUnauthorized
}
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
decoder := json.NewDecoder(resp.Body)
for {
select {
case <-c.t.Dying():
logger.Debugf("dying")
close(c.c)
return nil
case <-ctx.Done():
logger.Debugf("context canceled")
close(c.c)
return ctx.Err()
default:
var pollResp pollResponse
err = decoder.Decode(&pollResp)
if err != nil {View on GitHub (pinned to 909b515798)
Solutions
- Check the reported status code: 404 → wrong api_url/path, 403 → permissions, 5xx → LAPI or proxy problem
- Verify api_url, port, and route in the client's configuration (cscli bouncers / LAPI address)
- Check LAPI and any reverse-proxy logs around the failure time
- Confirm the client's credentials exist and are valid (cscli bouncers list / validate), then retry
Example fix
// before (config) api_url: http://127.0.0.1:8081/api/v1/wrong-route // after api_url: http://127.0.0.1:8080/
Defensive patterns
Strategy: retry
Validate before calling
# Before starting the poller, probe the endpoint:
curl -s -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $KEY" "$API_URL/watch/login/decision" Type guard
// Treat only 200 as success; handle known codes explicitly:
switch resp.StatusCode {
case http.StatusOK: /* proceed */
case http.StatusUnauthorized: /* re-auth */
default: return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
} Try / catch
if err := poller.Start(ctx); err != nil {
if strings.Contains(err.Error(), "unexpected status code") {
// log the code, check LAPI health, backoff and retry
time.Sleep(retryBackoff)
}
} Prevention
- Verify api_url and route reachability before deploying bouncers
- Check reverse-proxy timeouts for long-poll endpoints
- Keep client and LAPI versions compatible
- Validate bouncer credentials with cscli bouncers list
- Monitor LAPI health to catch 5xx before clients do
When it happens
Trigger: pollEvents → poll() receives resp.StatusCode != 200 and != 401: LAPI not reachable behind a reverse proxy returning 502/503, wrong URL/port in config (404), bouncer/user credentials valid enough to pass preflight but lacking rights (403), or LAPI crashed mid-request (500).
Common situations: Long-polling bouncers (appsec/notification setups) pointing at a wrong api_url; TLS proxy returning HTML error pages with 502; LAPI restarted during polling; version mismatch producing 404 on the poll route.
Related errors
- errUnauthorized
- error querying range: %w
- querying range: %w
- error tailing logs: %w
- api register (%s) http %s: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/999c36eae12fd15b.
Report an issue: GitHub.