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

  1. 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.
  2. Check what sits between the app and Elasticsearch (proxy, gateway, WAF) and verify it does not rewrite or replace response bodies.
  3. Log response headers and status to confirm the reply is actually from an Elasticsearch node, not an intermediary returning HTML with status 200.
  4. Ensure the Go Elasticsearch client version matches the server version; incompatible major versions can change response shapes.
  5. 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

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.