jaegertracing/jaeger · error

failed to create index: %w

Error message

failed to create index: %w

What it means

Returned by IndicesClient.CreateIndex when the HTTP PUT that creates an index fails with an error that is not a structured ResponseError (e.g. a transport-level failure). The wrapped err is the real cause. When ES does answer with a structured non-200 response, the ResponseError.prefixMessage variant naming the index is returned instead.

Source

Thrown at internal/storage/elasticsearch/esclient/index_client.go:177

		}
	}
	return nil
}

// CreateIndex an ES index
func (i *IndicesClient) CreateIndex(ctx context.Context, index string) error {
	_, err := i.request(ctx, elasticRequest{
		endpoint: index,
		method:   http.MethodPut,
	})
	if err != nil {
		var responseError ResponseError
		if errors.As(err, &responseError) {
			if responseError.StatusCode != http.StatusOK {
				return responseError.prefixMessage("failed to create index: " + index)
			}
		}
		return fmt.Errorf("failed to create index: %w", err)
	}
	return nil
}

// CreateAlias an ES specific set of index aliases
func (i *IndicesClient) CreateAlias(ctx context.Context, aliases []Alias) error {
	err := i.aliasAction(ctx, "add", aliases)
	if err != nil {
		var responseError ResponseError
		if errors.As(err, &responseError) {
			if responseError.StatusCode != http.StatusOK {
				return responseError.prefixMessage("failed to create aliases: " + i.aliasesString(aliases))
			}
		}
		return fmt.Errorf("failed to create aliases: %w", err)
	}
	return nil
}

View on GitHub (pinned to 806f444784)

Solutions

  1. Check ES connectivity (curl /_cluster/health) and fix address/credentials in the storage config
  2. Retry CreateIndex — ES returns 400 resource_already_exists_exception if it actually succeeded, so a re-run after a transient failure is safe
  3. Increase the client/request timeout if the cluster was slow to elect a master
  4. Unwrap the error (errors.Is/As on the %w chain) to find the underlying transport cause

Example fix

// before
if err := client.CreateIndex(ctx, "jaeger-span-000001"); err != nil {
    return err // transport failure indistinguishable from ES rejection
}
// after
if err := client.CreateIndex(ctx, "jaeger-span-000001"); err != nil {
    var respErr esclient.ResponseError
    if !errors.As(err, &respErr) {
        // transport-level failure: safe to retry
        return retryable(err)
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: cluster health
resp, err := http.Get(esURL + "/_cluster/health?wait_for_status=yellow&timeout=5s")
if err != nil || resp.StatusCode != 200 {
    return fmt.Errorf("ES unavailable, deferring CreateIndex")
}

Type guard

var respErr esclient.ResponseError
isTransportFailure := func(err error) bool {
    var re esclient.ResponseError
    return !errors.As(err, &re) // no structured ES response => retryable
}

Try / catch

if err := client.CreateIndex(ctx, index); err != nil {
    var respErr esclient.ResponseError
    if errors.As(err, &respErr) {
        return fmt.Errorf("ES rejected create (status %d): %w", respErr.StatusCode, err)
    }
    return retryWithBackoff(err) // CreateIndex is idempotent (already-exists => 400)
}

Prevention

When it happens

Trigger: PUT /<index> fails without a parseable ResponseError: network outage, connection reset, TLS error, or request context canceled before a response arrives.

Common situations: ES node down or restarting during Jaeger index initialization; wrong port/scheme in ES config; security proxy terminating the connection; short client timeout during cluster startup.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/e6f89422facdfa71. Report an issue: GitHub.