gofr-dev/gofr · error
%w: %w
Error message
%w: %w
What it means
Search() executes an Elasticsearch _search request and decodes the JSON response body into map[string]any. When json.Decoder.Decode fails — meaning the HTTP response body is not valid JSON or cannot unmarshal into the target — the call returns fmt.Errorf("%w: %w", errParsingResponse, err), wrapping both the library sentinel errParsingResponse and the underlying decode error. This means the request itself succeeded (no transport error, non-error status) but the body could not be parsed.
Source
Thrown at pkg/gofr/datasource/elasticsearch/elasticsearch.go:217
req := esapi.SearchRequest{
Index: indices,
Body: bytes.NewReader(body),
}
res, err := req.Do(tracedCtx, c.client)
if err != nil {
return nil, fmt.Errorf("%w: executing search: %w", errOperation, err)
}
defer res.Body.Close()
if res.IsError() {
return nil, fmt.Errorf("%w: %s", errResponse, res.String())
}
var result map[string]any
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("%w: %w", errParsingResponse, err)
}
c.sendOperationStats(start, "SEARCH", indices, "", query, span)
return result, nil
}
// Bulk executes multiple indexing/updating/deleting operations in one request.
// Each entry in `operations` should be a JSON‑serializable object
// following the Elasticsearch bulk API format.
func (c *Client) Bulk(ctx context.Context, operations []map[string]any) (map[string]any, error) {
if len(operations) == 0 {
return nil, errEmptyOperations
}
start := time.Now()
tracedCtx, span := c.addTrace(ctx, "bulk", nil, "")
View on GitHub (pinned to 187eb24962)
Solutions
- Inspect the wrapped error (errors.Unwrap / %v of the second error) to see the exact json syntax/unmarshal failure and the raw response via res.String() in logs.
- Check what sits between the app and Elasticsearch (proxy, gateway, WAF) and verify it does not rewrite or replace response bodies.
- Log response headers and status to confirm the reply is actually from an Elasticsearch node, not an intermediary returning HTML with status 200.
- Ensure the Go Elasticsearch client version matches the server version; incompatible major versions can change response shapes.
- Point the client directly at the ES node (bypass proxies) to isolate the cause.
Example fix
// before
result, err := esClient.Search(ctx, indices, query)
// after
result, err := esClient.Search(ctx, indices, query)
if err != nil {
if strings.Contains(err.Error(), errParsingResponse.Error()) {
// response body was not valid JSON; log endpoint/proxy details
logger.Errorf("elasticsearch returned unparseable body: %v", err)
}
return err
} Defensive patterns
Strategy: try-catch
Try / catch
result, err := client.Search(ctx, indices, query)
if err != nil {
if strings.Contains(err.Error(), "parsing") || strings.Contains(err.Error(), "invalid character") {
// body wasn't JSON: log endpoint, status, and any proxy details
return fmt.Errorf("elasticsearch search: non-JSON response: %w", err)
}
return err
} Prevention
- Monitor for intermediaries (proxies/WAFs) between app and ES and health-check that /_cluster/health returns JSON.
- Assert response content-type is application/json in integration tests with the real cluster.
- Keep ES Go client and server versions aligned.
When it happens
Trigger: Calling Search() where the ES node returns a 200 response whose body is not valid JSON: truncated/garbled responses, a proxy or middleware rewriting the body, HTML error pages served with a 200 status by a load balancer, or a response body already consumed before decoding.
Common situations: Reverse proxies or service meshes intercepting traffic and returning HTML; ES nodes behind misconfigured gateways; custom ES plugins altering responses; testing against a fake/mock server that returns malformed JSON; TLS-terminating proxies injecting content.
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
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/746cbf01220e198e.
Report an issue: GitHub.