jaegertracing/jaeger · error
invalid version format: %v
Error message
invalid version format: %v
What it means
ping calls the cluster info API and reads the Version["number"] field from the response. That field is expected to be a JSON string (e.g. "8.11.0"); if it is present under the "number" key but is not a string, ping refuses to guess and returns "invalid version format" with the actual value. Callers (ResolveBackendVersion) use this to pick ES vs OpenSearch code paths, so a wrong type would silently break version dispatch.
Source
Thrown at internal/storage/elasticsearch/esclient/version.go:39
Version map[string]any `json:"version"`
TagLine string `json:"tagline"`
}
body, err := c.request(ctx, elasticRequest{
endpoint: "",
method: http.MethodGet,
})
if err != nil {
return es.PingResult{}, err
}
var info clusterInfo
if err := json.Unmarshal(body, &info); err != nil {
return es.PingResult{}, err
}
versionField := info.Version["number"]
versionNumber, isString := versionField.(string)
if !isString {
return es.PingResult{}, fmt.Errorf("invalid version format: %v", versionField)
}
return es.PingResult{VersionNumber: versionNumber, TagLine: info.TagLine}, nil
}
View on GitHub (pinned to 806f444784)
Solutions
- Confirm the endpoint is a real Elasticsearch/OpenSearch node: curl http://host:9200/ and check version.number is a plain string.
- Check for proxies/LB that intercept / and return a transformed payload; point the client directly at the cluster.
- Update the Elasticsearch/Opensearch client library if the server version changed the info payload serialization.
- Inspect the value printed in the error to identify what the server actually returned (null suggests a missing/malformed response body).
Example fix
// before: hitting a proxy that returns {"version":{"number":8.1}}
server: "http://proxy:8080"
// after: hit the ES node directly
server: "http://es-node:9200" Defensive patterns
Strategy: type-guard
Validate before calling
// verify the endpoint returns a plain ES cluster info first
var info struct {
Version struct{ Number string `json:"number"` } `json:"version"`
}
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil || info.Version.Number == "" {
return fmt.Errorf("endpoint does not look like Elasticsearch")
} Type guard
func versionNumberIsString(info map[string]interface{}) (string, bool) {
v, ok := info["number"]
s, isStr := v.(string)
return s, ok && isStr
} Try / catch
pr, err := ResolveBackendVersion(ctx, client)
if err != nil {
if strings.Contains(err.Error(), "invalid version format") {
// endpoint is not returning a standard cluster-info payload;
// check what the server actually returned and fix the endpoint
}
return err
} Prevention
- Point Jaeger directly at a real Elasticsearch/OpenSearch node, not a proxy or LB that rewrites responses.
- Smoke-test the endpoint with curl and confirm version.number is a plain string before configuring storage.
- Pin and test against known server versions when upgrading the cluster.
- Capture the offending value from the error message to diagnose transformed/blocked responses quickly.
When it happens
Trigger: ResolveBackendVersion → ping against a server whose cluster info response has Version["number"] as a non-string (nil, map, or number) — e.g. a proxy or OpenSearch-compatible service returning an unexpected body shape.
Common situations: Pointing Jaeger at a non-Elasticsearch endpoint (proxy, load balancer HTML error page is JSON-wrapped oddly, or a custom mock); upgrading Elasticsearch where the info payload changed; a misconfigured endpoint returning a cluster-info-like body from a different product.
Related errors
- file must begin with '['
- max spans count reached
- empty configuration
- at least one storage backend is required
- cannot assign unique span ID, too many spans in the trace
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/a98c507f4d5eeb5b.
Report an issue: GitHub.