t8y2/dbx · error
etcd v2 server did not report X-Etcd-Index
Error message
etcd v2 server did not report X-Etcd-Index
What it means
currentEtcdIndex reads the X-Etcd-Index response header to learn the store's current revision. If the header is missing or not a valid integer, the function cannot determine the index and returns this error. The library requires a spec-compliant etcd v2 server that always sets this header on non-wait responses.
Source
Thrown at agents/drivers/etcd2-go/watch.go:266
return map[string]any{"watchId": watchID, "startedRevision": longString(waitIndex)}, nil
}
// currentEtcdIndex reads the X-Etcd-Index header from a lightweight GET.
func (c *authenticatedClient) currentEtcdIndex() (int64, error) {
ctx, cancel := context.WithTimeout(context.Background(), operationTimeout)
defer cancel()
response, err := c.request(ctx, http.MethodGet, "/v2/keys/", "", nil)
if err != nil {
return 0, err
}
defer drainClose(response.Body)
if response.StatusCode < 200 || response.StatusCode >= 300 {
body, _ := io.ReadAll(io.LimitReader(response.Body, 4096))
return 0, errorFromResponse(response.StatusCode, body)
}
index, err := strconv.ParseInt(response.Header.Get("X-Etcd-Index"), 10, 64)
if err != nil {
return 0, fmt.Errorf("etcd v2 server did not report X-Etcd-Index")
}
return index, nil
}
// pumpLongPollWatch drives the v2 wait loop: each response becomes one batch;
// timeouts and connection blips re-issue the same waitIndex.
func pumpLongPollWatch(ctx context.Context, client *authenticatedClient, key, scope string, waitIndex int64, includePrevKv bool, state *watchState) {
for {
if ctx.Err() != nil || state.hasTerminal() {
return
}
query := url.Values{}
query.Set("wait", "true")
query.Set("waitIndex", strconv.FormatInt(waitIndex, 10))
if scope == "prefix" {
query.Set("recursive", "true")
}
pollCtx, pollCancel := context.WithTimeout(ctx, watchPollTimeout)View on GitHub (pinned to c0390bff16)
Solutions
- Verify the endpoint is a genuine etcd v2 API server (curl -i and check X-Etcd-Index is present)
- Remove or fix proxies/load balancers that strip custom X-Etcd-* headers
- If using a test double, make the stub set X-Etcd-Index on responses
- Check etcd server version/upgrade notes for API changes
Example fix
// before (test stub)
w.Header().Set("Content-Type", "application/json")
// after
w.Header().Set("X-Etcd-Index", "42") Defensive patterns
Strategy: validation
Validate before calling
resp, err := http.Get(etcdURL)
if err == nil && resp.Header.Get("X-Etcd-Index") == "" {
// endpoint is not a compliant etcd v2 server; fix server/proxy first
} Try / catch
index, err := currentEtcdIndex(resp)
if err != nil {
return fmt.Errorf("endpoint does not look like etcd v2: %w", err)
} Prevention
- curl -i the endpoint and confirm X-Etcd-Index on responses
- Avoid proxies that strip X-Etcd-* headers
- Point at etcd 2.x API paths (/v2/keys), not v3 gateways
- Ensure test stubs set the header
When it happens
Trigger: Issuing an HTTP GET to an etcd v2 endpoint whose response lacks a parseable X-Etcd-Index header — the server is not really etcd v2, a proxy strips the header, or an empty/erroneous cluster response still returned a 2xx status.
Common situations: Pointing the driver at a mock/compat layer (e.g. an API gateway or v3-only server) that does not emit X-Etcd-Index; misconfigured load balancer dropping custom headers; testing against a stub HTTP server that forgot the header.
Related errors
- ETCD_V2_API_DISABLED
- Kafka broker does not support " + op.opType() + " config ope
- JDBC DriverManager rejected connect for URL '" + url + "'
- user is required
- Not connected
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/5f0a06e4e86af914.
Report an issue: GitHub.