googleapis/mcp-toolbox · error

elasticsearch error: status %s

Error message

elasticsearch error: status %s

What it means

Thrown in RunSQL when Elasticsearch returns an error response but its body cannot be parsed as JSON (DecodeJSON fails). The code falls back to reporting the HTTP status string (e.g. '400 Bad Request') since the detailed error reason was unreadable.

Source

Thrown at internal/sources/elasticsearch/elasticsearch.go:199

	res, err := esapi.EsqlQueryRequest{
		Body:       bytes.NewReader(body),
		Format:     format,
		FilterPath: []string{"columns", "values"},
		Instrument: s.ElasticsearchClient().InstrumentationEnabled(),
	}.Do(ctx, s.ElasticsearchClient())

	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		// Try to extract error message from response
		var esErr json.RawMessage
		err = util.DecodeJSON(res.Body, &esErr)
		if err != nil {
			return nil, fmt.Errorf("elasticsearch error: status %s", res.Status())
		}
		return esErr, nil
	}

	var result EsqlResult
	err = util.DecodeJSON(res.Body, &result)
	if err != nil {
		return nil, fmt.Errorf("failed to decode response body: %w", err)
	}

	output := EsqlToMap(result)

	return output, nil
}

// EsqlToMap converts the esqlResult to a slice of maps.
func EsqlToMap(result EsqlResult) []map[string]any {
	output := make([]map[string]any, 0, len(result.Values))

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Check the status string in the message and fix the underlying HTTP issue (e.g. 502/504 → check proxy; 400 → fix query)
  2. Bypass any proxy/load balancer and query Elasticsearch directly to get a real JSON error body
  3. Validate the ES|QL query syntax against the cluster (`POST /_query` with curl)
  4. Retry the query; transient gateway errors often return non-JSON bodies
Defensive patterns

Strategy: fallback

Validate before calling

// test the ES|QL query directly to get a real JSON error body
curl -u "$ES_USER:$ES_PASS" -H 'Content-Type: application/json' \
  'http://localhost:9200/_query?format=json' -d '{"query":"FROM index | LIMIT 10"}'

Try / catch

// Go: the returned error carries only the status; log it and retry or inspect server-side
out, err := src.RunSQL(ctx, format, query, params)
if err != nil && strings.Contains(err.Error(), "elasticsearch error: status") {
    slog.WarnContext(ctx, "ES error with unreadable body", "status", err)
    // fall back to direct cluster query for the detailed reason
}

Prevention

When it happens

Trigger: The ES|QL query endpoint returns an error (res.IsError()) whose body is empty, truncated, HTML (from a proxy/load balancer), or gzip/charset content the decoder cannot read — then the raw status is surfaced instead.

Common situations: Malformed ES|QL syntax triggering an error response behind a proxy that rewrites the body; intermediate gateways returning HTML 502/504 pages; response body already consumed or streaming interrupted.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/9fd493683edbdb9e. Report an issue: GitHub.