jaegertracing/jaeger · error

error starting cleaner server: %w

Error message

error starting cleaner server: %w

What it means

The storage-cleaner extension starts an internal HTTP server via c.server.ListenAndServe() in a goroutine to expose the purge endpoint. If ListenAndServe fails for any reason other than a clean shutdown (http.ErrServerClosed), the error is wrapped as 'error starting cleaner server' and reported as a fatal component status event to the OTel host, since the goroutine cannot return an error from Start.

Source

Thrown at cmd/jaeger/internal/integration/storagecleaner/extension.go:70

		if err := purger.Purge(r.Context()); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Purge request processed successfully"))
	}

	mux := http.NewServeMux()
	mux.HandleFunc("POST "+URL, purgeHandler)
	c.server = &http.Server{
		Addr:              ":" + c.config.Port,
		Handler:           mux,
		ReadHeaderTimeout: 3 * time.Second,
	}
	c.telset.Logger.Info("Starting storage cleaner server", zap.String("addr", c.server.Addr))
	go func() {
		if err := c.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			err = fmt.Errorf("error starting cleaner server: %w", err)
			componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(err))
		}
	}()

	return nil
}

func (c *storageCleaner) Shutdown(ctx context.Context) error {
	if c.server != nil {
		if err := c.server.Shutdown(ctx); err != nil {
			return fmt.Errorf("error shutting down cleaner server: %w", err)
		}
	}
	return nil
}

func (*storageCleaner) Dependencies() []component.ID {
	return []component.ID{jaegerstorage.ID}

View on GitHub (pinned to 806f444784)

Solutions

  1. Change the storagecleaner extension's server port/address to a free one (check with lsof/netstat for the conflicting listener)
  2. Stop the other process holding the port or configure it to use a different port
  3. Verify the configured address is bindable in your environment (0.0.0.0 vs localhost, container networking)

Example fix

// before
extensions:
  storagecleaner:
    server:
      endpoint: localhost:9877
// after  (port changed because 9877 was in use)
extensions:
  storagecleaner:
    server:
      endpoint: localhost:9878
Defensive patterns

Strategy: validation

Validate before calling

// before start, check the port is free
conn, err := net.Listen("tcp", "localhost:9877")
if err != nil { /* choose another port */ }
conn.Close()

Try / catch

// the extension reports a fatal status event; observe it
otelcol.Run returns the fatal error:
if err := cmd.Execute(); err != nil {
    if strings.Contains(err.Error(), "error starting cleaner server") {
        log.Fatalf("cleaner port in use: %v", err)
    }
}

Prevention

When it happens

Trigger: ListenAndServe returns a non-nil, non-ErrServerClosed error: the configured address/port is already in use, the port lacks permissions, or the listener fails at bind time.

Common situations: Port conflict with another process or a second jaeger instance using the same cleaner port; running in a container without the port published/bound; invalid bind address (e.g. wrong hostname).

Related errors


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