crowdsecurity/crowdsec · error
error decoding Loki response: %w
Error message
error decoding Loki response: %w
What it means
queryRange received HTTP 200 but the body could not be decoded into LokiQueryRangeResponse (invalid or structurally unexpected JSON). After retries are exhausted, the decode error is wrapped and returned.
Source
Thrown at pkg/acquisition/modules/loki/internal/lokiclient/loki_client.go:160
continue
}
if resp.StatusCode != http.StatusOK {
lc.Logger.Warnf("bad HTTP response code for query range: %d", resp.StatusCode)
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if ok := lc.shouldRetry(); !ok {
return fmt.Errorf("bad HTTP response code: %d: %s: %w", resp.StatusCode, string(body), err)
}
lc.increaseTicker(ticker)
continue
}
var lq LokiQueryRangeResponse
if err := json.NewDecoder(resp.Body).Decode(&lq); err != nil {
resp.Body.Close()
if ok := lc.shouldRetry(); !ok {
return fmt.Errorf("error decoding Loki response: %w", err)
}
lc.increaseTicker(ticker)
continue
}
resp.Body.Close()
lc.Logger.Tracef("Got response: %+v", lq)
c <- &lq
lc.resetFailStart()
if !infinite && (len(lq.Data.Result) == 0 || len(lq.Data.Result[0].Entries) < lc.config.Limit) {
lc.Logger.Infof("Got less than %d results (%d), stopping", lc.config.Limit, len(lq.Data.Result))
close(c)
return nil
}
if len(lq.Data.Result) > 0 {
lc.Logger.Debugf("(timer:%v) %d results / %d entries result[0] (uri:%s)", lc.currentTickerInterval, len(lq.Data.Result), len(lq.Data.Result[0].Entries), uri)
} else {
lc.Logger.Debugf("(timer:%v) no results (uri:%s)", lc.currentTickerInterval, uri)
}View on GitHub (pinned to 909b515798)
Solutions
- Inspect the raw response body via curl to see what Loki actually returns
- Check for auth redirects/proxies in front of Loki
- Align Loki version with the expected query_range response schema
Defensive patterns
Strategy: validation
Validate before calling
// probe raw body first:
// body, _ := io.ReadAll(resp); var probe map[string]any
// if json.Unmarshal(body, &probe) != nil || probe["data"] == nil { /* not a Loki API response */ } Try / catch
if err := json.NewDecoder(resp.Body).Decode(&lq); err != nil {
log.Errorf("non-JSON or unexpected Loki response; check for auth portal/proxy: %v", err)
return err
} Prevention
- Ensure no auth redirect or proxy injects HTML into the response
- Pin and test the Loki version compatibility
- Check response Content-Type is application/json
When it happens
Trigger: Loki returns HTML (auth portal, error page) with 200; an intermediate proxy mangles the body; a Loki version returns a different JSON schema.
Common situations: Basic-auth login pages returned with 200; reverse proxies intercepting requests; version mismatch between expected and actual Loki API response fields.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- invalid Loki entry: expected [timestamp, line], got %v
- error querying range: %w
- bad HTTP response code: %d: %s: %w
- invalid Loki entry: expected [timestamp, line], got %v
- missing: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/b65caeefd87f922d.
Report an issue: GitHub.