jaegertracing/jaeger · error

error creating Elasticsearch client

Error message

error creating Elasticsearch client: %w

What it means

This error is returned by the es-index-cleaner command when app.NewESClient fails to construct the Elasticsearch client after the config has loaded successfully. It wraps the underlying cause (%w), so the real reason (unreachable host, bad credentials, unsupported scheme) is appended to this message. It is a fatal startup error: the cleaner cannot do any work without a client.

Solutions

  1. Read the wrapped cause at the end of the message and fix that underlying issue (connection refused, 401, x509, etc.).
  2. Verify the Elasticsearch address argument is reachable: curl the URL from the same host/pod.
  3. Add the correct TLS/credential flags (ca, token, username/password) for a secured cluster.
  4. Ensure Elasticsearch is ready before the cleaner runs (init-container readiness check or retry logic).

Example fix

// before
esClient, err := app.NewESClient(ctx, "http://es:9200", cfg, logger)
// after — pass flags-derived config with auth/TLS set and verify URL first
if err := verifyESURL(esURL); err != nil { ... }
esClient, err := app.NewESClient(ctx, esURL, cfg, logger)
Defensive patterns

Strategy: validation

Validate before calling

esURL := args[1]
u, err := url.Parse(esURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid ES URL %q", esURL)
}
resp, err := http.Get(esURL)
if err != nil { return fmt.Errorf("ES unreachable: %w", err) }
resp.Body.Close()

Try / catch

if err := run(); err != nil {
    var esErr *app.ESClientError
    if errors.As(err, &esErr) { /* inspect wrapped cause */ }
    log.Fatal(err)
}

Prevention

When it happens

Trigger: Running es-index-cleaner with an Elasticsearch address argument that is unreachable, malformed, or requires auth/TLS that is not configured; NewESClient fails during ping/version discovery (e.g. trying to detect ES version via the root endpoint).

Common situations: Elasticsearch not yet up when a Kubernetes init-container/cronjob runs the cleaner; wrong ES URL or port; missing TLS/credential flags for a secured cluster; ES behind a proxy that blocks the version probe.

Related errors


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

Appendix: source

Thrown at cmd/es-index-cleaner/main.go:72

		Short: "Jaeger es-index-cleaner removes Jaeger indices",
		Long:  "Jaeger es-index-cleaner removes Jaeger indices",
		RunE: func(_ *cobra.Command, args []string) error {
			if len(args) != 2 {
				return errors.New("wrong number of arguments")
			}
			numOfDays, err := strconv.Atoi(args[0])
			if err != nil {
				return fmt.Errorf("could not parse NUM_OF_DAYS argument: %w", err)
			}

			if err := cfg.InitFromViper(v); err != nil {
				return fmt.Errorf("failed to initialize config: %w", err)
			}

			ctx := context.Background()
			esClient, err := app.NewESClient(ctx, args[1], cfg, logger)
			if err != nil {
				return fmt.Errorf("error creating Elasticsearch client: %w", err)
			}
			i := esclient.IndicesClient{
				Client:                 esClient,
				MasterTimeoutSeconds:   cfg.MasterNodeTimeoutSeconds,
				IgnoreUnavailableIndex: true,
			}

			indices, err := i.GetJaegerIndices(ctx, cfg.IndexPrefix)
			if err != nil {
				return err
			}

			deleteIndicesBefore := app.CalculateDeletionCutoff(time.Now().UTC(), numOfDays, relativeIndexCleaner.IsEnabled())
			logger.Info("Indices before this date will be deleted", zap.String("date", deleteIndicesBefore.Format(time.RFC3339)))

			filter := &app.IndexFilter{
				IndexPrefix:          cfg.IndexPrefix,
				IndexDateSeparator:   cfg.IndexDateSeparator,

View on GitHub (pinned to 806f444784)